在Python 3中
class A(object):
attr = SomeDescriptor()
...
def somewhere(self):
# need to check is type of self.attr is SomeDescriptor()
desc = self.__class__.__dict__[attr_name]
return isinstance(desc, SomeDescriptor)
有更好的方法吗?我不喜欢这个self.__class__.__dict__
的东西
答案 0 :(得分:13)
A.attr
会导致Python调用SomeDescriptor().__get__(None, A)
,因此当SomeDescriptor.__get__
为self
时inst
返回None
,A.attr
}将返回描述符:
class SomeDescriptor():
def __get__(self, inst, instcls):
if inst is None:
# instance attribute accessed on class, return self
return self
然后使用
访问描述符desc = type(self).attr
如果属性的名称仅作为字符串attr_name
知道,那么您将使用
desc = getattr(type(self), attr_name)
即使self
是A
的子类的实例,这也有效,而
desc = self.__class__.__dict__[attr_name]
仅在self
是A
的实例时才有效。
class SomeDescriptor():
def __get__(self, inst, instcls):
if inst is None:
# instance attribute accessed on class, return self
return self
return 4
class A():
attr = SomeDescriptor()
def somewhere(self):
attr_name = 'attr'
desc = getattr(type(self), attr_name)
# desc = self.__class__.__dict__[attr_name] # b.somewhere() would raise KeyError
return isinstance(desc, SomeDescriptor)
这表明A.attr
返回描述符,a.somewhere()
按预期工作:
a = A()
print(A.attr)
# <__main__.SomeDescriptor object at 0xb7395fcc>
print(a.attr)
# 4
print(a.somewhere())
# True
这表明它也适用于A
的子类。如果你取消注释
desc = self.__class__.__dict__[attr_name]
,你会看到
b.somewhere()
引发了一个KeyError:
class B(A): pass
b = B()
print(B.attr)
# <__main__.SomeDescriptor object at 0xb7395fcc>
print(b.attr)
# 4
print(b.somewhere())
# True
顺便说一下,即使你没有完全控制SomeDescriptor的定义,你仍然可以将它包装在一个描述符中,当self
为None时返回inst
:
def wrapper(Desc):
class Wrapper(Desc):
def __get__(self, inst, instcls):
if inst is None: return self
return super().__get__(inst, instcls)
return Wrapper
class A():
attr = wrapper(SomeDescriptor)()
def somewhere(self):
desc = type(self).attr
# desc = self.__class__.__dict__[attr_name] # b.somewhere() would raise KeyError
return isinstance(desc, SomeDescriptor)
所以没有必要使用
desc = self.__class__.__dict__[attr_name]
或
desc = vars(type(self))['attr']
遇到同样的问题。
答案 1 :(得分:8)
是的,要访问类的描述符,阻止descriptor.__get__
被调用的唯一方法是通过类__dict__
。
您可以使用type(self)
访问当前的类,vars()
可以使用更符合API的方式访问__dict__
:
desc = vars(type(self))['attr']
如果描述符完全是自定义的,如果实例参数为self
,则始终可以从SomeDescriptor.__get__()
返回None
,这在您访问描述符时会发生直接上课。您可以放弃vars()
来电并直接进入:
desc = type(self).attr
property()
描述符对象就是这样做的。