python - 为什么修改类属性不会修改 Python 中的对象属性?
问题描述
因此,如下面的代码片段所示,我无法完全理解 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
?
解决方案
混乱可能在obj.var += 1
指令中。
这相当于obj.var = obj.var + 1
. 右侧无法var
在对象上找到,因此委托给类。但是,左侧将结果存储在对象上。从那时起,查找var
对象将不再委托给类属性。
>>> 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
文档中的相关位:
类实例具有作为字典实现的命名空间,这是搜索属性引用的第一个位置。如果在那里找不到属性,并且实例的类具有该名称的属性,则使用类属性继续搜索。
关于您的后续问题,这是使用数据描述符做您想做的事情的一种方法,尽管我认为它不是非常 Pythonic。特别是,在类上有数据描述符是不寻常的(如果你不小心可能会破坏事情)。
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
推荐阅读
- android - Android ffmpeg 二进制和其他 .so 文件执行错误
- axios - Fetch 有效,但是当我使用 Axios 时出现 CORS 错误
- mongodb - 数据不移动到新的分片服务器 mongodb
- php - Chrome加载很长时间才能进入仪表板
- symfony - 根据实体属性ChoiceType多个属性(如何选择返回实体集合或一个实体)
- amazon-iam - 有没有办法为非活动的aws用户设置警报
- python-3.x - 烧瓶响应反斜杠问题
- python - 为什么即使输入是整数,我也会不断收到 TypeError?
- javascript - 如何在网站呈现之前检查 React/Gatsby 中的 window.innerWidth?
- tree - 使用队列的二叉树级别顺序遍历(数组实现)