Zacząłem intensywniej używać protokołu deskryptora python w kodzie, który pisałem. Zazwyczaj domyślna magia wyszukiwania pythona jest tym, co chcę, ale czasami odkrywam, że chcę uzyskać sam obiekt deskryptora zamiast wyników jego metody __get__
. Chcąc poznać typ deskryptora lub stan dostępu zapisany w deskryptorze lub coś takiego.Wyszukiwanie atrybutów python bez magii deskryptorów?
Napisałem poniższy kod, aby przejść do przestrzeni nazw w tym, co uważam za poprawne uporządkowanie, i zwrócić atrybut raw, niezależnie od tego, czy jest to deskryptor, czy nie. Jestem jednak zaskoczony, że nie mogę znaleźć wbudowanej funkcji lub czegoś w standardowej bibliotece, aby to zrobić - myślę, że to musi tam być i po prostu nie zauważyłem tego ani nie wybrałem go w wyszukiwarce.
Czy istnieje funkcja gdzieś w dystrybucji Pythona, która już to robi (lub coś podobnego)?
Dzięki!
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
Edit Wed, 28 października 2009.
odpowiedź Denisa dał mi konwencję do użycia w moich klasach deskryptorów, aby uzyskać deskryptor sprzeciwia się. Ale miałem całą klasę hierarchię klas deskryptora, a ja nie chciałem rozpocząć każdy__get__
funkcję z boilerplate
def __get__(self, instance, instance_type):
if instance is None:
return self
...
Aby tego uniknąć, zrobiłem korzeniem drzewa klasy dziedziczą z deskryptora następujące:
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)
Czasami chcesz obiekt deskryptora? To narusza podstawowe oczekiwania dla deskryptorów: powinny wyglądać jak atrybuty. Po co łamać podstawowe oczekiwania? Czemu to robić? Po co tworzyć coś tak złożonego? –
To, co robię, nie wydaje mi się * to * skomplikowane, ale myślę, że można powiedzieć, że eksperymentuję z projektem. W moim aktualnym, szczególnym przypadku mam deskryptor, który zwraca siłę broni w grze. Wartość ta jest funkcją stanu deskryptora (siła broni) i instancji (stanu zdrowia statku). Istnieją różne rodzaje broni; zwykle po prostu chcę uzyskać wartość, ale w kilku przypadkach muszę wiedzieć, jaka to broń - typ deskryptora. A jeśli deskryptor ma metody, które nie są częścią protokołu deskryptora, i czy chcesz do nich zadzwonić? –