因此,如下面的代码片段所示,我无法完全理解Python如何访问类变量。
class Test():
var = 1
obj = Test()
obj2 = Test()
print(Test.var, '\t',obj.var, '\t', obj2.var)
obj.var += 1
print(Test.var, '\t',obj.var, '\t', obj2.var)
Test.var += 5
print(Test.var, '\t',obj.var, '\t', obj2.var)
给出以下输出:
1 1 1 # Makes sense
1 2 1 # Also makes sense
6 2 6 # I would expect obj.var to become '7'
obj.var
保持不变。这是否意味着修改obj.var
创建了一个对象特定的变量,该变量现在独立于类属性var
?
答案 0 :(得分:1)
混乱可能在obj.var += 1
指令中。
这等效于obj.var = obj.var + 1
。右侧在对象上找不到var
,因此委托给该类。但是,左侧将结果存储在对象上。从那时起,在对象上查找var
将不再委托给class属性。
>>> class Test():
>>> var = 1
>>> Test.__dict__
mappingproxy({'__module__': '__main__',
'var': 1,
'__dict__': <attribute '__dict__' of 'Test' objects>,
'__weakref__': <attribute '__weakref__' of 'Test' objects>,
'__doc__': None})
>>> obj = Test()
>>> obj.__dict__
{}
>>> obj.var += 1
>>> obj.__dict__
{'var': 2}
如果删除对象属性,则再次暴露类属性:
>>> Test.var += 5
>>> obj.var
2
>>> del obj.var
>>> obj.var
6
the docs中的相关位:
一个类实例具有一个实现为字典的名称空间,这是搜索属性引用的第一位。如果在该位置找不到属性,并且实例的类具有该名称的属性,则搜索将继续使用该类的属性。
关于您的后续问题,这是使用data descriptors进行操作的一种方法,尽管我认为这不是Python语言。特别是,在类上具有数据描述符是不寻常的(如果不小心,可能会破坏事情)。
class VarDescriptorMetaclass(type):
"""Metaclass to allow data descriptor setters to work on types."""
def __setattr__(self, name, value):
setter = getattr(self.__dict__.get(name), '__set__')
return setter(None, value) if setter else super().__setattr__(name, value)
class VarDescriptor(object):
"""Data descriptor class to support updating property via both class and instance."""
def __init__(self, initial_value):
self.value = initial_value
def __get__(self, obj, objtype):
if obj and hasattr(obj, '_value'):
return self.value + obj._value
return self.value
def __set__(self, obj, value):
if obj:
obj._value = value - self.value
else:
self.value = value
def __delete__(self, obj):
if obj and hasattr(obj, '_value'):
del obj._value
class Test(metaclass=VarDescriptorMetaclass):
var = VarDescriptor(initial_value=1)
这似乎可以满足您的要求:
>>> obj = Test()
>>> obj.var
1
>>> obj.var += 1
>>> obj.var
2
>>> Test.var += 5
>>> Test.var
6
>>> obj.var
7