Ho iniziato a utilizzare il protocollo descrittore python in modo più esteso nel codice che ho scritto. In genere, la magia di ricerca python predefinita è ciò che voglio succedere, ma a volte sto cercando di ottenere l'oggetto descrittore invece dei risultati del suo metodo __get__
. Volendo conoscere il tipo di descrittore o lo stato di accesso memorizzato nel descrittore o qualcosa di simile.ricerca attributi Python senza magici descrittori?
Ho scritto il codice di seguito per percorrere gli spazi dei nomi in quello che ritengo sia l'ordine corretto e restituire l'attributo raw indipendentemente dal fatto che si tratti di un descrittore o meno. Sono sorpreso però che non riesca a trovare una funzione built-in o qualcosa nella libreria standard per farlo - immagino che debba esserci e io non l'ho notato o cercato su google per il giusto termine di ricerca.
Esiste qualche funzionalità nella distribuzione python che lo fa già (o qualcosa di simile)?
Grazie!
from inspect import isdatadescriptor
def namespaces(obj):
obj_dict = None
if hasattr(obj, '__dict__'):
obj_dict = object.__getattribute__(obj, '__dict__')
obj_class = type(obj)
return obj_dict, [t.__dict__ for t in obj_class.__mro__]
def getattr_raw(obj, name):
# get an attribute in the same resolution order one would normally,
# but do not call __get__ on the attribute even if it has one
obj_dict, class_dicts = namespaces(obj)
# look for a data descriptor in class hierarchy; it takes priority over
# the obj's dict if it exists
for d in class_dicts:
if name in d and isdatadescriptor(d[name]):
return d[name]
# look for the attribute in the object's dictionary
if obj_dict and name in obj_dict:
return obj_dict[name]
# look for the attribute anywhere in the class hierarchy
for d in class_dicts:
if name in d:
return d[name]
raise AttributeError
Modifica Mer 28 Ott, 2009.
risposta di Denis mi ha dato una convenzione da utilizzare nelle mie classi descrittori a farsi gli oggetti descrittore. Ma, ho avuto tutta una gerarchia di classi di classi descrittori, e non volevo iniziare ogni funzione__get__
con un testo standard
def __get__(self, instance, instance_type):
if instance is None:
return self
...
Per evitare questo, ho fatto la radice dell'albero di classe descrittore di ereditare da il seguente:
def decorate_get(original_get):
def decorated_get(self, instance, instance_type):
if instance is None:
return self
return original_get(self, instance, instance_type)
return decorated_get
class InstanceOnlyDescriptor(object):
"""All __get__ functions are automatically wrapped with a decorator which
causes them to only be applied to instances. If __get__ is called on a
class, the decorator returns the descriptor itself, and the decorated
__get__ is not called.
"""
class __metaclass__(type):
def __new__(cls, name, bases, attrs):
if '__get__' in attrs:
attrs['__get__'] = decorate_get(attrs['__get__'])
return type.__new__(cls, name, bases, attrs)
A volte si desidera l'oggetto descrittore? Ciò viola l'aspettativa principale dei descrittori: dovrebbero assomigliare a degli attributi. Perché rompere questa aspettativa fondamentale? Perché questo? Perché creare qualcosa di così complesso? –
Quello che sto facendo non mi sembra * così * complesso, ma immagino si possa dire che sto sperimentando il design. Nel mio attuale caso particolare, ho un descrittore che restituisce la forza di un'arma in un gioco. Quel valore è una funzione dello stato del descrittore (forza dell'arma) e dell'istanza (salute della nave). Esistono diversi tipi di armi; di solito voglio solo il risultato del valore, ma in alcuni casi, ho bisogno di sapere che tipo di arma è - il tipo del descrittore. E se un descrittore ha metodi che non fanno parte del protocollo descrittore e vuoi chiamarli? –