@staticmethod 和@classmethod 如何作用于python 中的变量?
How does @staticmethod and @classmethod act on the variable in python?
我写了一个简单的程序。
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'?。为什么即使在我使用 modifyUsingClassMethod()
使用 s1 实例更改了 num 的值后,输出仍显示 95,135
,为什么它在两种情况下都不使用 @staticmethod
和 @classmethod
进行更新?
我想当我使用 class 对象引用变量 num
时,python 将变量 num
视为实例变量,但是当我更改变量 num
使用 Class 名称,那么值不会在 s1
中更新,而是在 s2
中更新。我很困惑 @classmethod
和 @staticmethod
是如何工作的。
操作:
s1.num = s1.num + 5
导致 s1 包含 .num
的本地副本。如果您从测试代码中删除它,您会发现如果没有它,属性会随着时间的推移继续自我跟踪。
您的 class-method 和 static-method 都只会更改 class-level 变量。问题是你在实例变量 s1
中 隐藏了 你的 class-variable num
,当你这样做时:
s1.num = s1.num + 5
这创建了一个实例变量,它隐藏实例命名空间中的 class 变量。当你访问一个对象时,将检查实例的命名空间,如果没有找到具有该名称的属性,它将尝试classes name-space,然后它会检查所有的命名空间classes in the method-resultion-order: 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
的命名空间。
注意当我们从实例 name-space:
中删除 num
时会发生什么
In [11]: del s1.num
In [12]: s1.num
Out[12]: 140
我写了一个简单的程序。
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'?。为什么即使在我使用 modifyUsingClassMethod()
使用 s1 实例更改了 num 的值后,输出仍显示 95,135
,为什么它在两种情况下都不使用 @staticmethod
和 @classmethod
进行更新?
我想当我使用 class 对象引用变量 num
时,python 将变量 num
视为实例变量,但是当我更改变量 num
使用 Class 名称,那么值不会在 s1
中更新,而是在 s2
中更新。我很困惑 @classmethod
和 @staticmethod
是如何工作的。
操作:
s1.num = s1.num + 5
导致 s1 包含 .num
的本地副本。如果您从测试代码中删除它,您会发现如果没有它,属性会随着时间的推移继续自我跟踪。
您的 class-method 和 static-method 都只会更改 class-level 变量。问题是你在实例变量 s1
中 隐藏了 你的 class-variable num
,当你这样做时:
s1.num = s1.num + 5
这创建了一个实例变量,它隐藏实例命名空间中的 class 变量。当你访问一个对象时,将检查实例的命名空间,如果没有找到具有该名称的属性,它将尝试classes name-space,然后它会检查所有的命名空间classes in the method-resultion-order: 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
的命名空间。
注意当我们从实例 name-space:
中删除num
时会发生什么
In [11]: del s1.num
In [12]: s1.num
Out[12]: 140