Python 如何从类外访问类方法

Python 如何从类外访问类方法,python,Python,这是最简单的例子: class Foo(): def five(self): return 5 def bar(): print Foo.five() 如您所见,我想从bar调用five,但问题是类方法将self作为参数 我已经解决了这个问题,通过将Foo实例一直输入到bar,如下所示: class Foo(): def five(self): return 5 def bar(instance_of_Foo): prin

这是最简单的例子:

class Foo():
    def five(self):
        return 5

def bar():
    print Foo.five()
如您所见,我想从
bar
调用
five
,但问题是类方法将
self
作为参数

我已经解决了这个问题,通过将Foo实例一直输入到bar,如下所示:

class Foo():

    def five(self):
        return 5


def bar(instance_of_Foo):
    print Foo.five(instance_of_Foo)


foobar = Foo()

bar(foobar)
此解决方案的工作原理是,我可以将
Foo
的实例输入到对
bar()
的调用中。问题是在实例化
Foo
之前需要调用
bar()
,因为
Foo
对象是线程的目标

下面是一个更复杂的示例,演示了问题:

from tkinter import *
import threading
import time

count = 0

def counter():
    global count
    while True:
        count += 1
        print count
        time.sleep(1)

class GUI():
    def __init__(self):
        self.root = Tk()

    def five(self):
        global count

        self.var = StringVar()
        self.var.set(count)

        self.label = Label(self.root, textvariable=self.var)
        self.label.pack()

        self.root.mainloop()

def update_gui():
    global count
    while True:
        GUI.var = count
        GUI.root.update()

threads = []
t = threading.Thread(target=update_gui)
threads.append(t)
t.start()

countbot = threading.Thread(target=counter)
threads.append(countbot)
countbot.start()

foobar = GUI()
foobar.five()
上面的操作会引发此错误:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/Users/Henry/documents/python/blank3.py", line 36, in update_gui
    GUI.root.update()
AttributeError: class GUI has no attribute 'root'

这真的让我吃惊,因为GUI确实有一个名为root的属性。

您需要做的就是将函数标记为classmethod:

class Foo():

    @classmethod
    def five(cls):
        return 5

def bar():
    print Foo.five()

您只需将函数标记为classmethod:

class Foo():

    @classmethod
    def five(cls):
        return 5

def bar():
    print Foo.five()

首先,由于您既不依赖类也不依赖实例,简单的解决方案是:

也可以工作,但这是毫无意义的,除非有一些特定于类的行为,您希望根据可能的子类进行更改(您可以通过了解调用它的子类来获取信息);实际上,
@classmethod
实际上只适用于备用构造函数,在这里不适用

其次,
Foo
在您的代码示例中没有名为
self
的属性,因为您从未构造过
Foo
的实例,因此从未调用
\uuuu init\uuuu
来分配类属性。如果您想做类似的事情来创建一个单例实例,请不要在
\uuuuu init\uuuu
中这样做;定义类后立即执行,例如:

class Foo():
    ...
Foo.singleton = Foo()

同样,也不是特别有用,因此如果可能的话,我会避免使用它。

首先,简单的解决方案是:

也可以工作,但这是毫无意义的,除非有一些特定于类的行为,您希望根据可能的子类进行更改(您可以通过了解调用它的子类来获取信息);实际上,
@classmethod
实际上只适用于备用构造函数,在这里不适用

其次,
Foo
在您的代码示例中没有名为
self
的属性,因为您从未构造过
Foo
的实例,因此从未调用
\uuuu init\uuuu
来分配类属性。如果您想做类似的事情来创建一个单例实例,请不要在
\uuuuu init\uuuu
中这样做;定义类后立即执行,例如:

class Foo():
    ...
Foo.singleton = Foo()

同样,这不是特别有用,所以如果可能的话,我会避免使用它。

首先为什么需要
Foo
five
可以仅仅是一个函数而不是一个方法吗?@chepner
Foo
是证明这个问题的最简单的类的形式/例子,我想。是的,但是它不可能告诉我们正确的解决方案是将
five
变成一个类方法,一个静态方法,还是需要其他方法。我认为它被简化得太多了。解决编辑问题:你说你需要访问
self
,但描述一个
self
毫无意义的场景。试着提供一个例子来说明为什么
@classmethod
/
@staticmethod
不合适。例如,查看编写的代码,我只需跳过
bar
,并使用
foobar=Foo()
t=threading.thread(target=foobar.five)
创建线程。或者,如果
bar
必须是一个对象,那么给它一个参数来调用
five
,这样您就可以执行
t=threading.Thread(target=bar,args=(foobar,)
。如果需要,您甚至可以将参数设置为
Foo
的默认实例,这样就可以在不传递参数的情况下调用
bar
,并且它将重用默认设置的
Foo
。首先为什么需要
Foo
five
可以仅仅是一个函数而不是一个方法吗?@chepner
Foo
是证明这个问题的最简单的类的形式/例子,我想。是的,但是它不可能告诉我们正确的解决方案是将
five
变成一个类方法,一个静态方法,还是需要其他方法。我认为它被简化得太多了。解决编辑问题:你说你需要访问
self
,但描述一个
self
毫无意义的场景。试着提供一个例子来说明为什么
@classmethod
/
@staticmethod
不合适。例如,查看编写的代码,我只需跳过
bar
,并使用
foobar=Foo()
t=threading.thread(target=foobar.five)
创建线程。或者,如果
bar
必须是一个对象,那么给它一个参数来调用
five
,这样您就可以执行
t=threading.Thread(target=bar,args=(foobar,)
。如果需要,您甚至可以将参数设置为
Foo
的默认实例,这样就可以在不传递参数的情况下调用
bar
,它将重用默认的
Foo
。通常,
classmethod
用于替代构造函数(您需要知道调用它来构造相应子类的真实子类);如果您只是为返回常量的函数命名空间,那么您最好坚持使用
staticmethod
,避免接受(并忽略)
cls
。我已经编辑了这个问题;事实上,Five是一个更复杂的方法,需要访问self。一般来说,
classmethod
用于替代构造函数(您需要知道调用它来构造适当子类的真实子类);如果你只是给一个返回常量的函数命名,那么你最好坚持使用
staticmethod
,避免接受(或忽略)
cls
。我已经编辑了这个问题;实际上,5是一个muc