我正在自学Python,我最近的一课是Python不是Java,所以我刚刚花了一段时间把我所有的Class方法变成了函数。
我现在意识到,我不需要使用Class方法来做我在Java中使用静态方法所做的事情,但现在我不确定什么时候我会使用它们。我能找到的所有关于Python类方法的建议都是,像我这样的新手应该避开它们,而标准文档在讨论它们时是最不透明的。
谁有一个在Python中使用类方法的好例子,或者至少有人能告诉我什么时候可以合理地使用类方法吗?
我正在自学Python,我最近的一课是Python不是Java,所以我刚刚花了一段时间把我所有的Class方法变成了函数。
我现在意识到,我不需要使用Class方法来做我在Java中使用静态方法所做的事情,但现在我不确定什么时候我会使用它们。我能找到的所有关于Python类方法的建议都是,像我这样的新手应该避开它们,而标准文档在讨论它们时是最不透明的。
谁有一个在Python中使用类方法的好例子,或者至少有人能告诉我什么时候可以合理地使用类方法吗?
当前回答
替代构造函数是经典的例子。
其他回答
工厂方法(替代构造函数)确实是类方法的经典例子。
基本上,类方法适用于任何您希望有一个方法自然地适合类的名称空间,但不与类的特定实例相关联的时候。
例如,在excellent unipath模块中:
当前目录
Path.cwd () 返回实际的当前目录;例如,路径(“/ tmp / my_temp_dir”)。这是一个类方法。 .chdir () 使self为当前目录。
由于当前目录是进程范围的,cwd方法没有应该与之关联的特定实例。但是,将cwd更改为给定Path实例的目录确实应该是一个实例方法。
嗯…因为Path.cwd()确实返回了一个Path实例,我猜它可以被认为是一个工厂方法…
我也问过自己几次同样的问题。尽管这里的人试图努力解释它,恕我直言,我找到的最好的答案(也是最简单的)答案是Python文档中对Class方法的描述。
还有对静态方法的引用。如果有人已经知道实例方法(我假设是这样),这个答案可能是把它们放在一起的最后一块……
关于这个主题的进一步和更深入的阐述也可以在文档中找到: 标准类型层次结构(向下滚动到实例方法部分)
我从Ruby学到的是,所谓的类方法和所谓的实例方法只是一个函数,它的第一个参数具有语义意义,当函数作为对象的方法(即obj.meth())调用时,该参数会被无声地传递。
通常,该对象必须是一个实例,但@classmethod方法装饰器更改规则以传递一个类。你可以在一个实例上调用一个类方法(它只是一个函数)-第一个参数将是它的类。
因为它只是一个函数,所以在任何给定的作用域(即类定义)中只能声明一次。因此,对于ruby开发者来说,你不能让一个类方法和一个实例方法同名。
考虑一下:
class Foo():
def foo(x):
print(x)
你可以在实例上调用foo
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
但不是在课堂上:
Foo.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
现在添加@classmethod:
class Foo():
@classmethod
def foo(x):
print(x)
调用一个实例现在会通过它的类:
Foo().foo()
__main__.Foo
调用类也一样:
Foo.foo()
__main__.Foo
按照惯例,我们在实例方法中使用self作为第一个参数,在类方法中使用cls。我在这里用这两个都不是来说明它只是一个论点。在Ruby中,self是一个关键字。
与Ruby的对比:
class Foo
def foo()
puts "instance method #{self}"
end
def self.foo()
puts "class method #{self}"
end
end
Foo.foo()
class method Foo
Foo.new.foo()
instance method #<Foo:0x000000020fe018>
Python类方法只是一个装饰函数,您可以使用相同的技术来创建自己的装饰器。修饰过的方法包装了真正的方法(在@classmethod的情况下,它传递了额外的类参数)。底层的方法仍然存在,隐藏但仍然可以访问。
脚注:在类和实例方法之间的名称冲突引起了我的好奇心之后,我写了这篇文章。我不是Python专家,如果有任何错误,我希望得到评论。
@classmethod对于从外部资源轻松实例化该类的对象非常有用。考虑以下几点:
import settings
class SomeClass:
@classmethod
def from_settings(cls):
return cls(settings=settings)
def __init__(self, settings=None):
if settings is not None:
self.x = settings['x']
self.y = settings['y']
然后在另一个文件中:
from some_package import SomeClass
inst = SomeClass.from_settings()
访问inst.x将得到与settings['x']相同的值。
这是一个有趣的话题。我对它的理解是,python的classmethod操作起来像一个单例而不是一个工厂(它返回一个类的生成实例)。它是单例的原因是存在一个公共对象(字典),但只为类生成一次,但由所有实例共享。
为了说明这一点,这里有一个例子。注意,所有实例都有一个对单个字典的引用。这不是我理解的工厂模式。这可能是python独有的。
class M():
@classmethod
def m(cls, arg):
print "arg was", getattr(cls, "arg" , None),
cls.arg = arg
print "arg is" , cls.arg
M.m(1) # prints arg was None arg is 1
M.m(2) # prints arg was 1 arg is 2
m1 = M()
m2 = M()
m1.m(3) # prints arg was 2 arg is 3
m2.m(4) # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
M.m(5) # prints arg was 4 arg is 5