我无法理解在静态对象和成员对象(在构造函数中创建的对象)中发生了什么变化。
以下内容将运行被覆盖的获取():
class A(object):
class B(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return self.val
b = B(10, 'var "b"')
但是,如果我将b拉入构造函数,则不会:
class A(object):
class B(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return self.val
def __init__(self)):
self.b = A.B(10, 'var "b"')
我真的想在后者中完成这项工作,也许这不是正确的方法。
有人可以通过致电print(a.b)
a = A()
来解释这里发生的事情吗?
另外,有没有办法让print(a.b)
从b调用成员函数?
答案 0 :(得分:2)
通过实施__get__
,您将班级B
变为descriptor class。描述符是通过在实例上执行自定义逻辑来处理属性访问的对象。
为了使描述符起作用,您需要将它们声明为该类型的成员。只有这样,Python才能正确调用对象的__get__
和__set__
方法。
执行self.b = SomeDescriptor()
不起作用的原因是因为通过向self.b
分配内容,您直接更改了对象的基础__dict__
:
>>> class A(object): pass
>>> x = A()
>>> x.b = B(10, '')
>>> x.__dict__
{'b': <__main__.B object at 0x000000437141F208>}
正如您所看到的,x.b
具有该B
对象的值。那是描述符对象。当您尝试访问x.b
时,您只需返回该描述符对象。永远不会调用__get__
。
然而,当您在类型上设置描述符时,对象的b
中不存在成员__dict__
,因此Python将在继承链中进一步查找并找到{的描述符对象{1}}此时它还将执行描述符:
b
答案 1 :(得分:0)
您的b
对象是描述符。这意味着当Python被绑定为类变量时,Python对待它的方式与大多数其他对象不同。具体来说,在您的类变量代码中,A().b
变为函数调用A.__class__.__dict__["b"].__get__(A(), A)
。 Python在内部使用描述符。它是方法绑定和大多数__magic__
方法如何工作的一部分。
当描述符存储为实例变量时,不给出特殊处理。查找一个实例变量,该描述符只是获取描述符对象,而不是调用其__get__
方法的结果。
如果您需要能够在每个实例的基础上设置描述符返回的值,您可能希望让描述符检查它被调用的实例上的属性,而不是属性本身:
class B(object):
def __init__(self, name='var'):
self.name = name
def __get__(self, obj, objtype):
print('B Retrieving', self.name)
return obj._bval # lookup the value on the object, not on the descriptor
class A(object):
b = B() # assign the descriptor as an class variable
def __init__(self):
self._bval = 10 # initialize the value
请注意,我已经取消了您的课程,主要是为了清晰起见。在B
中定义A
类并不严格是错误的,但它令人困惑,并没有提供使B
成为顶级类的真正好处。