有没有像getattr/hasattr这样跳过实例属性的函数



有没有像标准库中的内置函数getattrhasattr这样的函数,但在属性查找过程中会跳过实例属性,比如特殊方法的隐式查找?

让我们将这些假设函数称为getclassattrhasclassattr。以下是我所期望的实现:

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实现,其中假设函数getclassattrhasclassattr在类type(self.__func__):*上查找属性'__get__'

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 here, not hasattr.
if hasclassattr(self.__func__, '__get__'):
# Note that we use getclassattr here, 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__')
class M(type):
pass
class C(metaclass=M):
def __get__(self, instance, owner=None):
pass
assert ClassMethod(C).__get__(123) == classmethod(C).__get__(123)

*注意,在self.__func__上调用假设函数getclassattrhasclassattr而不是在其上调用内置函数getattrhasattr是不起作用的,因为它们在实例self.__func__和类type(self.__func__):上都查找属性'__get__'

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):
pass
class C(metaclass=M):
def __get__(self, instance, owner=None):
pass
assert ClassMethod(C).__get__(123) != classmethod(C).__get__(123)

type(self.__func__)上调用内置函数getattrhasattr也不起作用,因为它们在实例type(self.__func__)和类type(type(self.__func__)):上都查找属性'__get__'

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(type(self.__func__), '__get__'):
return getattr(type(self.__func__), '__get__')(owner, type(owner))
return types.MethodType(self.__func__, owner)
@property
def __isabstractmethod__(self):
return hasattr(self.__func__, '__isabstractmethod__')
class MM(type):
def __get__(self, instance, owner=None):
pass
class M(type, metaclass=MM):
pass
class C(metaclass=M):
pass
assert ClassMethod(C).__get__(123) != classmethod(C).__get__(123)

在属性查找过程中引入新函数getclassattrhasclassattr来跳过实例属性,而不是像特殊方法的隐式查找一样,另一种方法是引入一个覆盖方法__getattribute__的代理类(我们称之为skip(。我认为这是一种更好的方法,因为方法__getattribute__是一个为自定义属性查找而设计的钩子,它与内置函数getattrhasattr一起工作,也与属性检索运算符.:一起工作

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'
assert getattr(skip(a), 'x') == 'class'
assert getattr(A, 'x') == 'class'
assert getattr(skip(A), 'x') == 'metaclass'

相关内容

  • 没有找到相关文章

最新更新