Python - self, 无 self 和 cls
又一个关于'self'是什么、如果不使用'self'会发生什么,以及'cls'是什么的问题。我“已经做了功课”,只是想确认我理解得是否正确。
self
- 要访问一个对象的属性,你需要在属性名前加上对象的名字(objname.attributename
)。同样,self
就是用来在对象(类)内部访问属性的。如果在类的方法中没有用self前缀一个变量,你就无法在这个类的其他方法中或者类外部访问这个变量。所以,如果你只想让这个变量在某个方法内部使用,可以不加self。如果你有一个方法,并且不需要与其他方法共享任何变量,也可以不把self
放在方法的参数里。
cls
- 每个实例都会创建自己属性的“副本”,所以如果你想让一个类的所有实例共享同一个变量,你需要在类声明中用cls
前缀这个变量名。
这样理解对吗?谢谢。
2 个回答
在普通的方法中,你会用 self
作为第一个参数,这样实例就会通过这个参数自动传递过来。也就是说,方法里的第一个参数指向的是当前的实例。
当一个方法加上 @classmethod
装饰器时,它的第一个参数会传入类,所以通常会把这个参数命名为 cls
,因为它指向的是类。
通常你不需要在变量名前加前缀(匈牙利命名法是不好的做法)。
下面是一个例子:
class Test(object):
def hello(self):
print 'instance %r says hello' % self
@classmethod
def greet(cls):
print 'class %r greet you' % cls
输出结果:
>>> Test().hello()
instance <__main__.Test object at 0x1f19650> says hello
>>> Test.greet()
class <class '__main__.Test'> greet you
self就像是用来访问对象(类)内部的属性。
其实不是在对象/类内部,而是在类的实例方法内部。self
只是一个约定,你可以把它叫成其他任何名字,甚至在每个方法里都用不同的名字。
所以如果你在类的方法里没有用self前缀一个变量,你就不能在类的其他方法里或者类外访问这个变量。
self
是在实例方法中使用的,而cls
通常是在类方法中使用的。其他的说法都是对的。
所以如果你只想让变量在那个方法内部使用,可以不加self。
没错,在一个方法里,变量名就像在其他任何函数里一样——解释器会先在本地查找这个名字,然后在闭包中查找,再然后在全局/模块级别查找,最后在Python内置函数中查找。
同样,如果你有一个方法,并且不想和其他方法共享任何变量,你可以不在方法参数中加self。
不行,你不能直接省略方法参数中的"self"。你必须告诉Python你想要一个staticmethod
,这样它就不会自动传递类的实例,可以通过在def
行上方加@staticmethod
,或者在方法体下面用mymethod = staticmethod(mymethod)
来实现。
每个实例都会创建自己的属性“副本”,所以如果你想让一个类的所有实例共享同一个变量,你需要在类声明中用'cls'前缀这个变量名。
在类定义内部,但在任何方法外部,名字是绑定到类上的——这就是你定义方法等的方式。你不需要在它们前面加cls
或其他任何东西。
cls
通常在__new__
这个特殊的staticmethod
中使用,或者在classmethod
中使用,创建方式和staticmethod
类似。这些方法只需要访问类,而不需要访问每个实例特有的东西。
在classmethod
内部,是的,你会用这个来指代你希望所有类的实例和类本身共享的属性。
和self
一样,cls
也只是一个约定,你可以把它叫成任何你想要的名字。
简单的例子:
class Foo(object):
# you couldn't use self. or cls. out here, they wouldn't mean anything
# this is a class attribute
thing = 'athing'
def __init__(self, bar):
# I want other methods called on this instance of Foo
# to have access to bar, so I create an attribute of self
# pointing to it
self.bar = bar
@staticmethod
def default_foo():
# static methods are often used as alternate constructors,
# since they don't need access to any part of the class
# if the method doesn't have anything at all to do with the class
# just use a module level function
return Foo('baz')
@classmethod
def two_things(cls):
# can access class attributes, like thing
# but not instance attributes, like bar
print cls.thing, cls.thing