我写了一个简单的程序。
class Sample:
num =45
def __init__(self):
print('Inside constructor')
@classmethod
def modifyUsingClassMethod(cls):
cls.num = cls.num + 45
@staticmethod
def modifyUsingStaticMethod():
Sample.num = Sample.num+5
s1 = Sample()
s2 = Sample()
s1.modifyUsingClassMethod()
print(s1.num, s2.num)
s1.num = s1.num + 5
print(s1.num)
s1.modifyUsingClassMethod()
print(s1.num, s2.num)
s1.modifyUsingStaticMethod()
print(s1.num, s2.num)
输出:
Inside constructor
Inside constructor
90 90
95
95 135
95 140
有人能解释一下
@staticmethod
和@classmethod
是如何作用于变量“num”的吗?。为什么在我使用95,135
更改了使用s1实例的num值之后,输出仍然显示modifyUsingClassMethod()
,为什么在使用@staticmethod
和@classmethod
两种情况下都不更新?我想当我使用类对象引用变量
num
时,python将变量num
视为实例变量,但是当我使用类名更改变量num
时,值不会在s1
中更新,而是在s2
中更新我非常困惑@classmethod
和@staticmethod
是如何工作的。 最佳答案
类方法和静态方法都只更改类级别变量。问题是,当您这样做时,您已经将类变量num
隐藏在实例变量s1
中:
s1.num = s1.num + 5
这将创建一个实例变量,在实例命名空间中隐藏类变量。访问对象时,将检查实例的命名空间,如果找不到具有该名称的属性,它将尝试类名称空间,然后按方法结果顺序检查所有类的命名空间:mro(这是继承)。
因此,考虑一下你的例子:
In [1]: class Sample:
...: num =45
...:
...: def __init__(self):
...: print('Inside constructor')
...:
...: @classmethod
...: def modifyUsingClassMethod(cls):
...: cls.num = cls.num + 45
...:
...: @staticmethod
...: def modifyUsingStaticMethod():
...: Sample.num = Sample.num+5
...:
In [2]: s1 = Sample()
...: s2 = Sample()
...:
...: s1.modifyUsingClassMethod()
...: print(s1.num,s2.num)
...:
...: s1.num = s1.num + 5
...: print(s1.num)
...:
...: s1.modifyUsingClassMethod()
...: print(s1.num,s2.num)
...:
...: s1.modifyUsingStaticMethod()
...: print(s1.num,s2.num)
...:
Inside constructor
Inside constructor
90 90
95
95 135
95 140
现在看看这些物体:
In [4]: vars(Sample)
Out[4]:
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
'__doc__': None,
'__init__': <function __main__.Sample.__init__>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'Sample' objects>,
'modifyUsingClassMethod': <classmethod at 0x107c3fe48>,
'modifyUsingStaticMethod': <staticmethod at 0x107c3ff98>,
'num': 140})
In [5]: vars(s1)
Out[5]: {'num': 95}
In [6]: vars(s2)
Out[6]: {}
您可以清楚地看到
s1
的名称空间中包含num
,并对Sample
的名称空间中的名称空间进行阴影处理。注意当我们从实例名称空间中删除
num
时会发生什么:In [11]: del s1.num
In [12]: s1.num
Out[12]: 140