我正在自学Python,我最近的一课是Python不是Java,所以我刚刚花了一段时间把我所有的Class方法变成了函数。
我现在意识到,我不需要使用Class方法来做我在Java中使用静态方法所做的事情,但现在我不确定什么时候我会使用它们。我能找到的所有关于Python类方法的建议都是,像我这样的新手应该避开它们,而标准文档在讨论它们时是最不透明的。
谁有一个在Python中使用类方法的好例子,或者至少有人能告诉我什么时候可以合理地使用类方法吗?
我正在自学Python,我最近的一课是Python不是Java,所以我刚刚花了一段时间把我所有的Class方法变成了函数。
我现在意识到,我不需要使用Class方法来做我在Java中使用静态方法所做的事情,但现在我不确定什么时候我会使用它们。我能找到的所有关于Python类方法的建议都是,像我这样的新手应该避开它们,而标准文档在讨论它们时是最不透明的。
谁有一个在Python中使用类方法的好例子,或者至少有人能告诉我什么时候可以合理地使用类方法吗?
当前回答
如果你不是一个“训练有素的程序员”,这应该会有帮助:
我想我已经理解了上面和网上其他地方的技术解释,但我总是有一个问题:“不错,但我为什么需要它?”什么是实际的用例?”现在生活给了我一个很好的例子来阐明一切:
我使用它来控制由多线程模块实例化的类的实例之间共享的全局共享变量。在人性化的语言中,我正在运行多个代理,为深度学习并行创建示例。(想象多个玩家同时玩ATARI游戏,每个人都将他们的游戏结果保存到一个公共存储库(SHARED VARIABLE))
我用以下代码实例化玩家/代理(在主/执行代码中):
a3c_workers = [A3C_Worker(self.master_model, self.optimizer, i, self.env_name, self.model_dir) for i in range(multiprocessing.cpu_count())]
它创造了和我的电脑上有多少处理器核心一样多的玩家 A3C_Worker——定义代理的类 A3c_workers -是该类实例的列表(即每个实例都是一个玩家/代理)
现在我想知道所有玩家/代理玩了多少游戏,因此在A3C_Worker定义中,我定义了所有实例共享的变量:
class A3C_Worker(threading.Thread):
global_shared_total_episodes_across_all_workers = 0
现在,当工人们完成他们的游戏时,每完成一场比赛,他们都会增加1个数字
在我的示例生成结束时,我关闭了实例,但共享变量已经分配了所玩游戏的总数。所以当我重新运行它时,我最初的总集数是之前的总和。但是我需要这个计数来代表每次单独运行的值
为了解决这个问题,我指定:
class A3C_Worker(threading.Thread):
@classmethod
def reset(cls):
A3C_Worker.global_shared_total_episodes_across_all_workers = 0
在执行代码中调用:
A3C_Worker.reset()
注意,它是对CLASS整体的调用,而不是它单独的任何实例。因此,从现在开始,对于我发起的每个新代理,它将把我的计数器设置为0。
使用通常的方法定义def play(self):,将需要我们为每个实例单独重置计数器,这将需要更多的计算,并且难以跟踪。
其他回答
工厂方法(替代构造函数)确实是类方法的经典例子。
基本上,类方法适用于任何您希望有一个方法自然地适合类的名称空间,但不与类的特定实例相关联的时候。
例如,在excellent unipath模块中:
当前目录
Path.cwd () 返回实际的当前目录;例如,路径(“/ tmp / my_temp_dir”)。这是一个类方法。 .chdir () 使self为当前目录。
由于当前目录是进程范围的,cwd方法没有应该与之关联的特定实例。但是,将cwd更改为给定Path实例的目录确实应该是一个实例方法。
嗯…因为Path.cwd()确实返回了一个Path实例,我猜它可以被认为是一个工厂方法…
当用户登录我的网站时,user()对象从用户名和密码实例化。
如果我需要一个没有用户在那里登录的用户对象(例如,一个管理用户可能想要删除另一个用户帐户,所以我需要实例化该用户并调用它的delete方法):
我有类方法来获取用户对象。
class User():
#lots of code
#...
# more code
@classmethod
def get_by_username(cls, username):
return cls.query(cls.username == username).get()
@classmethod
def get_by_auth_id(cls, auth_id):
return cls.query(cls.auth_id == auth_id).get()
我也问过自己几次同样的问题。尽管这里的人试图努力解释它,恕我直言,我找到的最好的答案(也是最简单的)答案是Python文档中对Class方法的描述。
还有对静态方法的引用。如果有人已经知道实例方法(我假设是这样),这个答案可能是把它们放在一起的最后一块……
关于这个主题的进一步和更深入的阐述也可以在文档中找到: 标准类型层次结构(向下滚动到实例方法部分)
@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']相同的值。
替代构造函数是经典的例子。