我正在寻找作为默认类和函数参数存在的默认参数object
, self
的含义,因此远离它,如果我们调用类的属性,我们应该使用Foo
(类引用)还是应该使用Foo()
(类的实例)。
如果你是阅读一个正常的属性,那么这并不重要。如果您要绑定一个普通属性,那么您必须使用正确的属性才能使代码正常工作。如果你要访问一个描述符,那么你必须使用实例。
python类语义的细节在数据模型中有很好的文档。特别是__get__
语义在这里起作用。实例基本上是将它们的命名空间堆叠在类的命名空间之上,并添加一些用于调用方法的样板文件。
这里有一些很大的"这取决于你在做什么"的陷阱。最重要的问题是:您想访问类还是实例属性?第二,你想要属性还是方法?
让我们举个例子:
class Foo(object):
bar = 1
baz = 2
def __init__(self, foobar="barfoo", baz=3):
self.foobar = foobar
self.baz = baz
def meth(self, param):
print self, param
@classmethod
def clsmeth(cls, param):
print cls, param
@staticmethod
def stcmeth(param):
print param
这里,bar
是一个类属性,所以你可以通过Foo.bar
获得它。由于实例对其类名称空间具有隐式访问,因此也可以将其作为Foo().bar
获取。foobar
是一个实例属性,因为它从来没有绑定到类(只有实例,即self
s) -你只能得到它作为Foo().foobar
。最后,baz
是一个类和一个实例属性。默认为Foo.baz == 2
和Foo().baz == 3
,因为类属性被__init__
中的实例属性集隐藏。
同样,在赋值操作中,处理类还是处理实例也有细微的区别。Foo.bar=2
将设置class属性(也适用于所有实例),而Foo().bar=2
将创建一个实例属性,该实例属性为该特定实例遮蔽class属性。
对于方法来说,情况有点类似。然而,这里您获得了实例方法的隐式self
参数(如果是为类定义的函数)。基本上,调用Foo().meth(param=x)
被静默地转换为Foo.meth(self=Foo(), param=x)
。这就是为什么调用Foo.meth(param=x)
通常是无效的——meth没有"绑定"到实例,因此缺少self
参数。
现在,有时您不需要方法中的任何实例数据—例如,您有严格的字符串转换,这是一个更大的解析器类的实现细节。这就是@classmethod
和@staticmethod
发挥作用的地方。类方法的第一个参数始终是类,而不是常规方法的实例。Foo().clsmeth(param=x)
和 Foo.clsmeth(param=x)
导致呼叫clsmethod(cls=Foo, param=x)
。这里,这两个是等价的。更进一步,静态方法不获取任何类或实例信息—它就像绑定到类名称空间的原始函数。