Sto cercando di capire come ottenere i nomi di tutti i decoratori su un metodo. Posso già ottenere il nome del metodo e docstring, ma non riesco a capire come ottenere un elenco di decoratori.Introspection per ottenere nomi decoratori su un metodo?
risposta
Se è possibile cambiare il modo di chiamare i decoratori da
class Foo(object):
@many
@decorators
@here
def bar(self):
pass
a
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
allora si potrebbe registrare i decoratori in questo modo:
def register(*decorators):
def register_wrapper(func):
for deco in decorators[::-1]:
func=deco(func)
func._decorators=decorators
return func
return register_wrapper
Ad esempio:
def many(f):
def wrapper(*args,**kwds):
return f(*args,**kwds)
return wrapper
decos = here = many
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
foo=Foo()
Qui accedere alla tupla di decoratori:
print(foo.bar._decorators)
# (<function many at 0xb76d9d14>, <function decos at 0xb76d9d4c>, <function here at 0xb76d9d84>)
Qui si stampa solo i nomi dei decoratori:
print([d.func_name for d in foo.bar._decorators])
# ['many', 'decos', 'here']
Questa è un'ottima soluzione. : D Suppone che tu abbia accesso al codice che sta assegnando i decoratori, però ... – Faisal
Ok questo potrebbe funzionare, ma perché non posso semplicemente aggiungere il codice func._whatever = 'qualcosa' nel mio decoratore esistente, e testare per il valore dell'attributo _whatever quando si esegue l'introspezione sul metodo? – Tony
Puoi, ma poi dovrai sporcare ogni decoratore che scrivi con la preoccupazione trasversale di lasciare le sue tracce nella funzione che modifica. – Faisal
Questo a mio parere non è possibile. Un decoratore non è una sorta di attributo o metadati di un metodo. Un decoratore è una comoda sintassi per la sostituzione di una funzione con il risultato di una chiamata di funzione. Vedi http://docs.python.org/whatsnew/2.4.html?highlight=decorators#pep-318-decorators-for-functions-and-methods per maggiori dettagli.
E 'impossibile fare in modo generale, perché
@foo
def bar ...
è esattamente lo stesso di
def bar ...
bar = foo (bar)
Si può fare in alcuni casi particolari, come probabilmente @staticmethod
analizzando oggetti funzione , ma non meglio di così.
Questo perché i decoratori sono "zucchero sintattico". Diciamo che avete il seguente decoratore:
def MyDecorator(func):
def transformed(*args):
print "Calling func " + func.__name__
func()
return transformed
E lo si applica ad una funzione:
@MyDecorator
def thisFunction():
print "Hello!"
Ciò equivale a:
thisFunction = MyDecorator(thisFunction)
Si potrebbe incorporare una "storia" nella funzione oggetto, forse, se hai il controllo dei decoratori. Scommetto che c'è un altro modo intelligente per farlo (forse per incarico preponderante), ma sfortunatamente non sono molto esperto in Python. :(
Come Faisal notes, si potrebbe avere i decoratori si attaccano i metadati alla funzione, ma a mia conoscenza non è fatto automaticamente.
Non è possibile, per definizione.Decorator:
@dec
def foo():
return 1
è solo scorciatoia per:
def foo_internal()
return 1
foo = dec(foo_internal)
Si noti che, decoratore dec
è semplicemente un po 'di qualcosa di callable ritorno (funzione, forse qualche altro oggetto callable). Non so nemmeno se foo
ha nulla a che fare con la definizione decorato, per esempio:
def dec(f):
def not_foo():
return 0
return not_foo
Se avete bisogno di mettere un po 'ulteriori informazioni sui metodi, classi ecc .--- come ad esempio attributi in .NET --- imposta semplicemente alcuni attributi su di essi.
def foo()
return 1
foo.decorated = True
Oppure implementare decoratori che impostano tali attributi, se è davvero utile per la leggibilità.
def dec(f):
f.decorated = True
return f
Bene. Python è open-source. Puoi sempre estendere l'interprete Python per tracciare i decoratori applicati all'oggetto. Poiché (come mostrato sopra) l'oggetto restituito dal decoratore non deve essere correlato in alcun modo all'oggetto decorato, questa implementazione dovrebbe memorizzare le informazioni dall'oggetto decorato prima di applicare il decoratore, applicare il decoratore, sostituire le informazioni del decoratore sull'oggetto restituito e aggiungere informazioni sull'ultimo decoratore.
Può essere fatto. Ma non sono sicuro che sia davvero utile. E aggiunge un po 'di spese generali ad ogni decoratore. Quindi non mi aspetto un tale meccanismo nel mainstream Python, a meno che non offra altri vantaggi, come la semplificazione dell'implementazione di decoratori, ecc.
"Non è possibile, per definizione" sembra una risposta errata al 100%, dato che Jaymon ha pubblicato come farlo con il pacchetto di riflessione standard ("import inspect") sopra. http://stackoverflow.com/a/31197273/1424877 Suggerisco di cancellare questa risposta ... a meno che non mi manchi qualcosa di sottile. – Quuxplusone
Non si può, ma peggio ancora, esistono librerie per nascondere il fatto che si ha decorato una funzione per cominciare. Vedere Functools o la libreria decoratore (@decorator
se potessi trovarlo) per ulteriori informazioni.
Sono sorpreso che questa domanda è così vecchio e nessuno ha avuto il tempo di aggiungere il modo attuale introspettiva per fare questo, ecco che è:
Il codice che si desidera ispezionare ...
def template(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
baz = template
che = template
class Foo(object):
@baz
@che
def bar(self):
pass
Ora è possibile controllare quanto sopra Foo
classe con qualcosa di simile ...
import ast
import inspect
def get_decorators(cls):
target = cls
decorators = {}
def visit_FunctionDef(node):
decorators[node.name] = []
for n in node.decorator_list:
name = ''
if isinstance(n, ast.Call):
name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id
else:
name = n.attr if isinstance(n, ast.Attribute) else n.id
decorators[node.name].append(name)
node_iter = ast.NodeVisitor()
node_iter.visit_FunctionDef = visit_FunctionDef
node_iter.visit(ast.parse(inspect.getsource(target)))
return decorators
print get_decorators(Foo)
questo dovrebbe stampare qualcosa di simile ...
{'bar': ['baz', 'che']}
o almeno lo ha fatto quando ho provato questo con Python 2.7.9 reale veloce :)
Ok, questo ha problemi in python 3: (almeno sembra, e sono sicuro di non essere * la persona migliore con la conoscenza di inspect/ast per commentare con quel livello di certezza); fondamentalmente ho un codice da quello che hai sopra, e 'inspect.getsource()' sembra tornare con gli spazi davanti al 'def wrapper', che poi dà un errore di rientro imprevisto sulla chiamata' ast.parse' . – Jmons
* ANCHE * quando ho provato a dimostrarlo usando gli strumenti di run-script hte online (che credo piuttosto che eseguire script da un file), ho ottenuto "OSError: codice sorgente non disponibile" quindi sospetto che ci siano istanze (forse anche bin runs) dove questo processo non funzionerà. Forse non funzionerà quando esistono solo percorsi di python di python? – Jmons
Quale versione di python3? L'ho appena testato in Python 2.7.13 e Python 3.6.4 (che sono le versioni che ho sul mio computer) ed entrambi hanno funzionato bene. Inoltre, non sono sicuro che funzionerà ovunque, ma ha funzionato ovunque ne avessi avuto bisogno. Potrei sicuramente vedere lo script di esecuzione online con protezioni per moduli come ast e inspect, e probabilmente altre cose come l'apertura di file, poiché è, per definizione, un ambiente più contenuto. – Jaymon
- 1. Python Introspection: come ottenere i nomi dei metodi di classe?
- 2. Objective C Introspection/Reflection
- 3. Decoratori su metodi astratti
- 4. __decorated__ per decoratori Python
- 5. Decoratori del metodo di implementazione in C#
- 6. Ottenere i nomi dei parametri di un metodo di interfaccia
- 7. Introspection pacchetto Java
- 8. Introspection in Clojure
- 9. D: nome parametro funzione introspection
- 10. Utilizzo di decoratori su lambda in Python?
- 11. Che cos'è il "completamento del codice basato su Introspection"?
- 12. Ruby on Rails Attributo record attivo Introspection
- 13. Metodo scanner per ottenere un carattere
- 14. Usare lsof per ottenere un elenco di nomi di file
- 15. decoratori Python nelle classi
- 16. Decoratori ed ereditarietà Python
- 17. Fili con decoratori
- 18. Decoratori di funzioni annidate che operano su argomenti in python
- 19. Esiste una scorciatoia in Eclipse per generare codice per decoratori?
- 20. C'è qualcosa come decoratori pitone per C#?
- 21. Differenza tra intercettori e decoratori
- 22. Python Decoratori - __call__ in classe
- 23. autofac - registrare più decoratori
- 24. JavaScript decoratori HOWTO?
- 25. Come ottenere nomi brevi per il mese in Joda Time?
- 26. Come posso ottenere un elenco di spazi dei nomi su App Engine di Google?
- 27. Decoratori in stile Python in Java?
- 28. Convenzioni di denominazione Python nei decoratori
- 29. decoratori funzione con parametri su una vista basata classe Django
- 30. decoratori di funzioni in C#
Questo sembra inutile. Hai la fonte. Cosa c'è di sbagliato leggendo la fonte? –
@ S.Lott: non potreste rispondere allo stesso modo a qualsiasi domanda riguardante l'introspezione? Eppure l'introspezione è utile. –
@ S.Lott: Non c'è niente di sbagliato nella lettura dell'origine, praticamente come se nulla fosse sbagliato leggendo i contenuti di un database direttamente invece di usare viste o script, a meno che non voglia l'automazione. Uso i decoratori per l'autenticazione e sto generando report con visualizzazioni diverse per mostrare quali gruppi di utenti hanno accesso a quali risorse. Quindi ho bisogno di un accesso programmatico alla sorgente, come se avessi bisogno di un accesso programmatico a un'origine dati. – Tony