我试图了解 self
和 cls
之间是否存在差异,但我很挣扎,尽管存在很多关于这个主题的讨论。例如:
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
我不明白如果两种方法相同的话调用类成员的意义是什么?我知道这是这个论坛上的一个常见问题,但我真的不明白为什么我们会使用不同的单词来指代同一件事(我们甚至可以使用任何变量名称而不是 self
或 cls
)。
更新
在以下情况下:
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.A
和 self.A
并不引用同一个变量。
最佳答案
所有您的方法都是实例方法。它们都不是类方法。
方法的第一个参数仅按照惯例命名为self
。您可以将其命名为任何您想要的名称,并将其命名为 cls
不会使其成为对该类的引用。第一个参数绑定(bind)到实例是由于方法查找的工作方式(访问 C.getA_s
生成绑定(bind)方法对象,调用该对象会导致 C
被传递到原始函数 getA_s
中),参数名称不起作用。
在您的方法中,您仅引用实例属性。 A
属性最终仅在类上定义并不重要,您仍然可以通过 C.A
访问该属性(其中 C
是您创建的实例),而不是 maclass.A
。如果没有实例属性遮蔽它,则在实例上查找属性也会找到在类上定义的属性。
要使方法成为类方法,请用 @classmethod
decorator 修饰它:
@classmethod
def getA_c(cls):
print(cls.A)
现在 cls
将始终是对类的引用,而不是对实例的引用。我需要再次强调,对于 Python 来说,我为第一个参数选择什么名称实际上并不重要,但是 cls 是这里的约定,因为这样可以更容易地提醒读者该方法是绑定(bind)的到类对象。
请注意,如果您对 getB_c()
方法执行此操作,则尝试在该方法中访问 cls.B
将失败,因为没有 B
属性。maclass
类对象上的
这是因为 classmethod
将函数包装在 descriptor object 中它会覆盖正常的函数绑定(bind)行为。当作为实例上的属性访问时,正是描述符协议(protocol)导致方法绑定(bind)到实例,classmethod
对象会重定向该绑定(bind)过程。
这是一个带有内联注释的简短演示,我使用 Python 转换来命名类(使用 CamelCase),以及实例、属性、函数和方法(使用 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'
请注意,即使我们在实例上设置了同名的属性,类方法也会访问类属性。
接下来是绑定(bind)行为:
>>> 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'>>
绑定(bind)方法告诉您它们绑定(bind)到什么,调用该方法时会传入该绑定(bind)对象作为第一个参数。还可以通过查看绑定(bind)方法的 __self__ 属性来自省(introspection)该对象:
>>> instance.get_instance_attribute.__self__ # the instance
<__main__.MyClass object at 0x10f92b5f8>
>>> instance.get_class_attribute.__self__ # the class
<class '__main__.MyClass'>
关于python - 了解 `self` 和 `cls` 之间的区别以及它们是否引用相同的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48880314/