الثعبان السمة البحث دون أي السحر واصف؟
-
06-07-2019 - |
سؤال
ولقد بدأت في استخدام بروتوكول الثعبان اصف أكثر على نطاق واسع في كود لقد تم كتابة. عادة، الثعبان بحث السحر الافتراضي هو ما أريد أن يحدث، ولكن في بعض الأحيان أجد أريد الحصول على الكائن واصف نفسه بدلا نتائج طريقة __get__
لها. يريد أن يعرف نوع واصف، أو دولة الوصول المخزنة في واصف، أو شيء سومساك.
وكتبت رمز أدناه على المشي مساحات في ما أعتقد هو الترتيب الصحيح، والعودة السمة الخام بغض النظر عن ما إذا كان واصف أم لا. أنا مندهش على الرغم من أنني لا يمكن العثور على وظيفة المضمنة أو شيء في المكتبة القياسية للقيام بذلك - الرقم الأول يجب أن يكون هناك وأنا فقط لم يلاحظ أو غوغليد لمصطلح البحث الصحيح.
هل هناك وظيفة في مكان ما في توزيع الثعبان أن يفعل هذا بالفعل (أو ما شابه)؟
وشكرا!
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
وتحرير الأربعاء، 28 أكتوبر 2009.
والجواب دينيس وأعطاني اتفاقية لاستخدامها في الفصول الدراسية واصف لي للحصول على واصف الكائنات أنفسهم. ولكن، كان لي التسلسل الهرمي فئة كاملة من فئات واصف، وأنا لم أكن أريد أن أبدأ <م> كل م> وظيفة __get__
مع النمطي
def __get__(self, instance, instance_type):
if instance is None:
return self
...
لتجنب هذا الأمر، أنا جعلت جذر شجرة الطبقة اصف يرث ما يلي:
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)
المحلول
ومعظم اصفات القيام بعملهم عند الوصول إليها كما المثال السمة فقط. حتى أنها مريحة للعودة نفسه عندما يكون الوصول إليها لفئة:
class FixedValueProperty(object):
def __init__(self, value):
self.value = value
def __get__(self, inst, cls):
if inst is None:
return self
return self.value
وهذا يتيح لك الحصول على واصف نفسه:
>>> class C(object):
... prop = FixedValueProperty('abc')
...
>>> o = C()
>>> o.prop
'abc'
>>> C.prop
<__main__.FixedValueProperty object at 0xb7eb290c>
>>> C.prop.value
'abc'
>>> type(o).prop.value
'abc'
ملحوظة، أن هذا يعمل ل(أكثر؟) المدمج في واصفات أيضا:
>>> class C(object):
... @property
... def prop(self):
... return 'abc'
...
>>> C.prop
<property object at 0xb7eb0b6c>
>>> C.prop.fget
<function prop at 0xb7ea36f4>
والوصول إلى واصف يمكن أن تكون مفيدة عندما تحتاج إلى حد أنه في فئة فرعية، ولكن هناك <لأ href = "https://stackoverflow.com/questions/101268/hidden-features-of-python/1631763#1631763" > أفضل طريقة للقيام بذلك.
نصائح أخرى
وتوفر المكتبة inspect
وظيفة لاسترداد سمة من دون أي السحر واصف: inspect.getattr_static
وثائق: https://docs.python.org /3/library/inspect.html#fetching-attributes-statically
و(هذا هو السؤال القديم، ولكن أظل القادمة عبر عندما أحاول أن أتذكر كيفية القيام بذلك، لذلك أنا نشر هذا الجواب حتى أتمكن من العثور عليه مرة أخرى!)
والأسلوب أعلاه
class FixedValueProperty(object):
def __init__(self, value):
self.value = value
def __get__(self, inst, cls):
if inst is None:
return self
return self.value
هل طريقة عظيمة كلما يمكنك التحكم رمز للممتلكات، ولكن هناك بعض الحالات، مثل عند الخاصية هي جزء من مكتبة يسيطر عليها شخص آخر، حيث نهج آخر هو مفيد. هذا نهج بديل يمكن أيضا أن تكون مفيدة في حالات أخرى مثل تنفيذ رسم الخرائط وجوه، والمشي اسم الفضاء كما هو موضح في السؤال، أو غيرها من المكتبات المتخصصة.
والنظر في فئة مع خاصية بسيطة:
class ClassWithProp:
@property
def value(self):
return 3
>>>test=ClassWithProp()
>>>test.value
3
>>>test.__class__.__dict__.['value']
<property object at 0x00000216A39D0778>
عند الوصول إليها من الطبقة كائنات حاوية على ديكت ، أو يتم تجاوز "السحر واصف. لاحظ أيضا أنه إذا كنا تعيين الخاصية إلى متغير فئة جديدة، فإنه يتصرف تماما مثل الأصلي مع "السحر واصف، ولكن إن وجد إلى متغير المثال، الخاصية يتصرف مثل أي كائن طبيعي وأيضا يتجاوز" السحر واصف ".
>>> test.__class__.classvar = test.__class__.__dict__['value']
>>> test.classvar
3
>>> test.instvar = test.__class__.__dict__['value']
>>> test.instvar
<property object at 0x00000216A39D0778>
ودعونا نقول أننا نريد للحصول على واصف لobj.prop
حيث type(obj) is C
.
وC.prop
عادة ما تعمل لواصف عادة ما يعود نفسه عند الوصول إليها عبر C
(أي، منضما إلى C
). ولكن قد يؤدي C.prop
واصف في metaclass لها. إذا كانت prop
يست موجودة في obj
، فإن obj.prop
رفع AttributeError
في حين قد لا C.prop
. لذلك فمن الأفضل استخدام inspect.getattr_static(obj, 'prop')
.
إذا كنت غير راض عن ذلك، وهنا طريقة سي بايثون محددة (من _PyObject_GenericGetAttrWithDict
في Objects/object.c
):
import ctypes, _ctypes
_PyType_Lookup = ctypes.pythonapi._PyType_Lookup
_PyType_Lookup.argtypes = (ctypes.py_object, ctypes.py_object)
_PyType_Lookup.restype = ctypes.c_void_p
def type_lookup(ty, name):
"""look for a name through the MRO of a type."""
if not isinstance(ty, type):
raise TypeError('ty must be a type')
result = _PyType_Lookup(ty, name)
if result is None:
raise AttributeError(name)
return _ctypes.PyObj_FromPtr(result)
وtype_lookup(type(obj), 'prop')
يعود واصف في بنفس الطريقة عندما يستخدم سي بايثون ذلك في obj.prop
إذا obj
هو كائن المعتاد (وليس الطبقة، على سبيل المثال).