我正在自学Python,我最近的一课是Python不是Java,所以我刚刚花了一段时间把我所有的Class方法变成了函数。

我现在意识到,我不需要使用Class方法来做我在Java中使用静态方法所做的事情,但现在我不确定什么时候我会使用它们。我能找到的所有关于Python类方法的建议都是,像我这样的新手应该避开它们,而标准文档在讨论它们时是最不透明的。

谁有一个在Python中使用类方法的好例子,或者至少有人能告诉我什么时候可以合理地使用类方法吗?


当前回答

我认为最明确的答案是AmanKow的答案。归根结底,这取决于你想如何组织你的代码。你可以把所有东西都写成模块级的函数,这些函数被包装在模块的命名空间中

module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass


usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass 
def f5():pass

usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()

上面的过程代码组织得不好,正如你所看到的,只有3个模块后,它变得令人困惑,每个方法是做什么的?你可以为函数使用较长的描述性名称(如在java中),但你的代码仍然很快变得难以管理。

面向对象的方法是将代码分解为可管理的块,即类和对象,函数可以与对象、实例或类相关联。

与模块级函数相比,使用类函数可以在代码中获得另一个级别的除法。 因此,您可以在类中对相关函数进行分组,使它们更特定于分配给该类的任务。例如,你可以创建一个文件工具类:

class FileUtil ():
  def copy(source,dest):pass
  def move(source,dest):pass
  def copyDir(source,dest):pass
  def moveDir(source,dest):pass

//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")

这种方式更灵活,更可维护,您将函数分组在一起,并且每个函数的功能更明显。此外,您还可以防止名称冲突,例如,函数副本可能存在于您在代码中使用的另一个导入模块中(例如网络副本),因此当您使用全名FileUtil.copy()时,您可以消除这个问题,并且两个复制函数可以并排使用。

其他回答

Think about it this way: normal methods are useful to hide the details of dispatch: you can type myobj.foo() without worrying about whether the foo() method is implemented by the myobj object's class or one of its parent classes. Class methods are exactly analogous to this, but with the class object instead: they let you call MyClass.foo() without having to worry about whether foo() is implemented specially by MyClass because it needed its own specialized version, or whether it is letting its parent class handle the call.

当您在创建实际实例之前进行设置或计算时,类方法是必不可少的,因为在实例存在之前,您显然不能将实例用作方法调用的调度点。在SQLAlchemy源代码中可以看到一个很好的例子;在下面的链接中查看dbapi()类方法:

https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47

You can see that the dbapi() method, which a database backend uses to import the vendor-specific database library it needs on-demand, is a class method because it needs to run before instances of a particular database connection start getting created — but that it cannot be a simple function or static function, because they want it to be able to call other, supporting methods that might similarly need to be written more specifically in subclasses than in their parent class. And if you dispatch to a function or static class, then you "forget" and lose the knowledge about which class is doing the initializing.

当用户登录我的网站时,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()

工厂方法(替代构造函数)确实是类方法的经典例子。

基本上,类方法适用于任何您希望有一个方法自然地适合类的名称空间,但不与类的特定实例相关联的时候。

例如,在excellent unipath模块中:

当前目录

Path.cwd () 返回实际的当前目录;例如,路径(“/ tmp / my_temp_dir”)。这是一个类方法。 .chdir () 使self为当前目录。

由于当前目录是进程范围的,cwd方法没有应该与之关联的特定实例。但是,将cwd更改为给定Path实例的目录确实应该是一个实例方法。

嗯…因为Path.cwd()确实返回了一个Path实例,我猜它可以被认为是一个工厂方法…

替代构造函数是经典的例子。

诚实?我从未发现staticmethod或classmethod的用途。我还没有看到一个操作不能使用全局函数或实例方法来完成。

如果python像Java那样使用private和protected成员,情况将有所不同。在Java中,我需要一个静态方法来访问实例的私有成员来做一些事情。在Python中,很少需要这样做。

通常,我看到人们使用静态方法和类方法,而他们真正需要做的只是更好地使用python的模块级名称空间。