【发布时间】:2021-07-09 23:40:00
【问题描述】:
是否有类似标准库中的内置函数getattr 和hasattr 但在属性查找期间绕过实例属性 的函数,例如implicit lookup of special methods?
我们将这些假设函数称为getclassattr 和hasclassattr。以下是我期望的实现:
null = object()
def getclassattr(obj, name, default=null, /):
if not isinstance(name, str):
raise TypeError('getclassattr(): attribute name must be string')
try:
classmro = vars(type)['__mro__'].__get__(type(obj))
for cls in classmro:
classdict = vars(type)['__dict__'].__get__(cls)
if name in classdict:
attr = classdict[name]
attrclassmro = vars(type)['__mro__'].__get__(type(attr))
for attrclass in attrclassmro:
attrclassdict = vars(type)['__dict__'].__get__(attrclass)
if '__get__' in attrclassdict:
return attrclassdict['__get__'](attr, obj, type(obj))
return attr
classname = vars(type)['__name__'].__get__(type(obj))
raise AttributeError(f'{classname!r} object has no attribute {name!r}')
except AttributeError as exc:
try:
classmro = vars(type)['__mro__'].__get__(type(obj))
for cls in classmro:
classdict = vars(type)['__dict__'].__get__(cls)
if '__getattr__' in classdict:
return classdict['__getattr__'](obj, name)
except AttributeError as exc_2:
exc = exc_2
except BaseException as exc_2:
raise exc_2 from None
if default is not null:
return default
raise exc from None
def hasclassattr(obj, name, /):
try:
getclassattr(obj, name)
except AttributeError:
return False
return True
用例是内置类classmethod:*的纯Python实现
import types
class ClassMethod:
def __init__(self, function):
self.__func__ = function
def __get__(self, instance, owner=None):
if instance is None and owner is None:
raise TypeError('__get__(None, None) is invalid')
if owner is None:
owner = type(instance)
# NOT hasattr.
if hasclassattr(self.__func__, '__get__'):
# NOT getattr.
return getclassattr(self.__func__, '__get__')(owner, type(owner))
return types.MethodType(self.__func__, owner)
@property
def __isabstractmethod__(self):
return hasattr(self.__func__, '__isabstractmethod__')
* 请注意,此实现不适用于内置函数 getattr 和 hasattr,因为它们首先在实例属性中查找,因为与内置类 classmethod 的比较表明:
>>> import types
>>> class ClassMethod:
... def __init__(self, function):
... self.__func__ = function
... def __get__(self, instance, owner=None):
... if instance is None and owner is None:
... raise TypeError('__get__(None, None) is invalid')
... if owner is None:
... owner = type(instance)
... if hasattr(self.__func__, '__get__'):
... return getattr(self.__func__, '__get__')(owner, type(owner))
... return types.MethodType(self.__func__, owner)
... @property
... def __isabstractmethod__(self):
... return hasattr(self.__func__, '__isabstractmethod__')
...
>>> class M(type):
... def __get__(self, instance, owner=None): return 'metaclass'
...
>>> class A(metaclass=M):
... def __get__(self, instance, owner=None): return 'class'
>>> ClassMethod(A).__get__('foo')
'class'
>>> classmethod(A).__get__('foo')
'metaclass'
【问题讨论】:
-
为什么不只是...在类上使用
getattr或hasattr,而不是在实例上使用? -
@KarlKnechtel:这会导致元类和描述符出现问题。
-
@KarlKnechtel 因为这也会在元类上查找属性,所以
ClassMethod(a).__get__(3)将在最后一个代码 sn-p 中返回'metaclass'(而不是'class')。 -
恐怕我还是不明白这个问题。您能否展示
getclassattr实现的示例直接 执行与应用于类的内置getattr不同的操作? -
@KarlKnechtel 是:
class A: x = 'foo'; a = A(); a.x = 'bar'; print(getattr(a, 'x')); print(getclassattr(a, 'x'))打印bar\nfoo。
标签: python attributes idioms standard-library class-variables