getattr
和hasattr
这样的函数,在属性查找时跳过实例属性,比如特殊方法的隐式查找?
我们将这些假设函数称为
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
:*
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)
# Note that we use hasclassattr instead of hasattr here.
if hasclassattr(self.__func__, '__get__'):
# Note that we use getclassattr instead of getattr here.
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'
与其引入新函数
getclassattr
和 hasclassattr
在属性查找期间跳过实例属性(如 特殊方法的隐式查找),另一种方法是引入一个代理类(我们称之为 skip
),覆盖方法__getattribute__
。我认为这可能是一个更好的方法,因为方法 __getattribute__
是一个为自定义属性查找而设计的钩子,它可以与内置函数 getattr
和 hasattr
一起使用,而且还可以与属性检索运算符 .
一起使用:
class skip:
def __init__(self, subject):
self.subject = subject
def __getattribute__(self, name):
obj = super().__getattribute__('subject')
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}')
class M(type):
x = 'metaclass'
class A(metaclass=M):
x = 'class'
a = A()
a.x = 'object'
assert getattr(a, 'x') == 'object' and getattr(skip(a), 'x') == 'class'
assert getattr(A, 'x') == 'class' and getattr(skip(A), 'x') == 'metaclass'