我写了一个简单的程序。

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

10-06 07:16
查看更多