了解``自我''和``cls''之间的区别以及它们是否指的是相同的属性



我试图了解selfcls之间是否存在差异,但我正在挣扎,即使存在很多关于此主题的讨论。例如:

class maclass():
    A = "class method"
    def __init__(self):
        self.B = "instance method"
    def getA_s(self):
        print(self.A)
    def getA_c(cls):
        print(cls.A)
    def getB_s(self):
        print(self.B)
    def getB_c(cls):
        print(cls.B)
C = maclass()
C.getA_s()
C.getA_c()
C.getB_s()
C.getB_c()

给我:

class method
class method
instance method
instance method

因此,无论是使用self还是cls,它总是指相同的变量。当我在Init__中添加self.A时,CLS.A刚刚替换

def __init__(self):
        self.B = "instance method"
        self.A = "new instance method"

我得到:

new instance method
new instance method
instance method
instance method

我不明白有两种方法可以打电话给班级成员的意义吗?我知道这是这个论坛上的一个常见问题,但我真的不明白为什么我们会使用不同的单词来指代同一件事(我们甚至可以使用任何可变名称而不是selfcls(。

更新

在以下情况下:

class maclass():
    A = "class method, "
    def __init__(self):
        self.A = "instance method, "
    def getA_s(self):
        print(self.A) #give me "instance method, "
    @classmethod
    def getA_c(cls):
        print(cls.A) #give me "class method, "
C = maclass()
C.getA_s()
C.getA_c()
print(' ')
print(C.A) #give me "instance method, "

我得到:

instance method, 
class method, 
instance method,    

因此,在这种情况下,在maclass中:cls.Aself.A不参考相同的变量。

所有您的方法是实例方法。它们都不是类方法。

仅通过justnunt的第一个参数为 self命名。您可以将其命名为任何想要的东西,而将其命名为cls不会使其成为对类的引用。第一个参数绑定到一个实例是由于方法查找的工作原理(访问C.getA_s产生A bound方法对象,并调用该对象导致C传递到原始函数getA_s(,名称(参数的无角色。

在您的方法中,您只是引用实例属性。A属性最终仅在类上定义,您仍在通过C.A访问该属性(其中C是您创建的实例(,而不是maclass.A。查找实例上的属性还将在类上找到属性,如果没有实例属性阴影。

要使方法成为类方法,请用@classmethod装饰器进行装饰:

@classmethod
def getA_c(cls):
    print(cls.A)

现在cls始终是对类的引用,而不是实例。我需要再次强调,python我为第一个参数选择了什么名字并不重要,但是cls是这里的约定,因为这使得更容易提醒读者此方法绑定到类对象。

请注意,如果您为getB_c()方法执行此操作,则尝试在该方法中访问cls.B,因为maclass class Object上没有B属性。

那是因为classmethod将函数包裹在描述符对象中,从而覆盖了正常函数绑定行为。描述符协议导致方法在实例上访问时被绑定到实例, classmethod对象重定向绑定过程。

这是一个带有内联注释的简短演示,我使用了命名类(使用骆驼(的python转换,以及实例,属性,函数和方法(使用snake_case(:

>>> class MyClass():
...     class_attribute = "String attribute on the class"
...     def __init__(self):
...         self.instance_attribute = "String attribute on the instance"
...     @classmethod
...     def get_class_attribute(cls):
...         return cls.class_attribute
...     def get_instance_attribute(self):
...         return self.instance_attribute
...     @classmethod
...     def get_instance_attribute_on_class(cls):
...         return cls.instance_attribute
...
>>> instance = MyClass()
>>> instance.class_attribute  # class attributes are visible on the instance
'String attribute on the class'
>>> MyClass.class_attribute   # class attributes are also visible on the class
'String attribute on the class'
>>> instance.get_class_attribute()  # bound to the class, but that doesn't matter here
'String attribute on the class'
>>> instance.class_attribute = "String attribute value overriding the class attribute"
>>> instance.get_class_attribute()  # bound to the class, so the class attribute is found
'String attribute on the class'
>>> MyClass.get_instance_attribute_on_class()   # fails, there is instance_attribute on the class
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 12, in get_instance_attribute_on_class
AttributeError: type object 'MyClass' has no attribute 'instance_attribute'

请注意,类方法即使我们在实例上设置了具有相同名称的属性,也可以访问类属性。

接下来是绑定行为:

>>> MyClass.get_instance_attribute   # accessing the method on the class gives you the function
<function MyClass.get_instance_attribute at 0x10f94f268>
>>> instance.get_instance_attribute  # accessing the method on the instance gives you the bound method
<bound method MyClass.get_instance_attribute of <__main__.MyClass object at 0x10f92b5f8>>
>>> MyClass.get_class_attribute      # class methods are always bound, to the class
<bound method MyClass.get_class_attribute of <class '__main__.MyClass'>>
>>> instance.get_class_attribute     # class methods are always bound, to the class
<bound method MyClass.get_class_attribute of <class '__main__.MyClass'>>

绑定的方法告诉您它们被绑定到,称该方法通过该界对象作为第一个参数传递。该对象也可以通过查看绑定方法的__self__属性来进行内省:

>>> instance.get_instance_attribute.__self__  # the instance
<__main__.MyClass object at 0x10f92b5f8>
>>> instance.get_class_attribute.__self__     # the class
<class '__main__.MyClass'>

最新更新