在Python中访问类的成员变量?


83
class Example(object):
    def the_example(self):
        itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

如何访问类的变量?我尝试添加此定义:

def return_itsProblem(self):
    return itsProblem

但是,这也失败了。


1
标题编辑,问题实际上有关类的“静态”变量:stackoverflow.com/questions/707380/...
西罗桑蒂利郝海东冠状病六四事件法轮功

Answers:


139

简而言之,答案

在您的示例中,itsProblem是一个局部变量。

您必须使用self设置和获取实例变量。您可以在__init__方法中进行设置。那么您的代码将是:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

但是,如果您想要一个真正的类变量,则直接使用类名:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)

但要小心这一点,因为theExample.itsProblem它会自动设置为等于Example.itsProblem,但根本不是同一变量,可以独立更改。

一些解释

在Python中,可以动态创建变量。因此,您可以执行以下操作:

class Example(object):
    pass

Example.itsProblem = "problem"

e = Example()
e.itsSecondProblem = "problem"

print Example.itsProblem == e.itsSecondProblem 

版画

真正

因此,这正是您使用前面的示例所做的。

的确,在Python中我们使用selfas this,但还不止于此。self是任何对象方法的第一个参数,因为第一个参数始终是对象引用。无论您是否调用,这都是自动的self

这意味着您可以:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

要么:

class Example(object):
    def __init__(my_super_self):
        my_super_self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

完全一样。ANY对象方法的第一个参数是当前对象,我们仅将其self称为约定。然后,您只需要向该对象添加一个变量即可,就像从外部执行该操作一样。

现在,关于类变量。

当您这样做时:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

您会注意到我们首先设置一个类变量,然后访问一个对象(实例)变量。我们从来没有设置这个对象变量,但是它起作用了,那怎么可能呢?

好吧,Python尝试首先获取对象变量,但是如果找不到它,则会为您提供类变量。警告:在实例之间共享类变量,而在对象变量之间不共享。

结论是,切勿使用类变量将默认值设置为对象变量。使用__init__了点。

最终,您将了解到Python类是实例,因此是对象本身,这为理解上述内容提供了新的见解。一旦意识到这一点,请稍后再阅读。


您说:“ theExample.itsProblem会自动设置为等于Example.itsProblem,但根本不是相同的变量,可以独立更改”-但这并不完全正确,您的短语具有误导性。我相信您知道那里发生了什么,所以建议改写一下:“它相同的变量,但是可以为每个对象独立地重新绑定”。
jsbueno

是的,但是绑定是完全未知的其他编程语言(例如Java或C(我怀疑是OP))的概念。然后,我将解释什么是绑定,然后是后期绑定,然后是可变对象上的引用问题。太久了 我认为有时候您必须在理解的祭坛上牺牲精度。
e-satis 2010年

还有(我认为可能是2.7+)@classmethod装饰器,值得研究。有趣的讨论,在这里- stackoverflow.com/questions/12179271/...
JSH

1
名称绑定:无论级别如何,提供虚假陈述都是一个坏主意。我建议进行一下稍微的修改:但是要小心一点,因为theExample.itsProblem它会自动设置为等于Example.itsProblem,但是从实际的角度来看,*根本不是同一变量,可以独立更改。*:实际上它始于同一个对象,但是很容易意外更改,如果您不了解Python的名称绑定
n611x007 2014年

11

您声明的是局部变量,而不是类变量。要设置实例变量(属性),请使用

class Example(object):
    def the_example(self):
        self.itsProblem = "problem"  # <-- remember the 'self.'

theExample = Example()
theExample.the_example()
print(theExample.itsProblem)

要设置类变量(又称静态成员),请使用

class Example(object):
    def the_example(self):
        Example.itsProblem = "problem"
        # or, type(self).itsProblem = "problem"
        # depending what you want to do when the class is derived.

1
除了在类级别一次声明类变量外。您的方式将在每次实例化时将其重置,这确实不是您想要的。另请参阅stackoverflow.com/questions/2709821/python-self-explaned,以了解显式self背后的原理。

2

如果您有一个实例函数(即通过自我传递的实例函数),则可以使用self通过以下方式获取对该类的引用 self.__class__

例如,在下面的代码中,龙卷风创建了一个实例来处理获取请求,但是我们可以控制get_handler该类并使用它来容纳一个riak客户,因此我们不需要为每个请求都创建一个。

import tornado.web
import riak

class get_handler(tornado.web.requestHandler):
    riak_client = None

    def post(self):
        cls = self.__class__
        if cls.riak_client is None:
            cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
        # Additional code to send response to the request ...
    

这是一个很好的示例,可以从OP的原始标题中演示问题。实际上,OP的示例与标题不匹配,其他答案参考该示例。无论如何,这是访问类级别变量的最佳方法,因为它不违反DRY原理。像其他一些例子一样。最好使用self .__ class__而不是重复类名。它使代码更适合将来使用,使重构更容易,并且如果您敢于使用子类化,这也将具有优势。
麻省理工学院

应当警告读者,使用上述处理程序不仅会在非单线程应用程序中导致问题,还应引起注意。从理论上讲,该类的多个实例可以并行使用同一处理程序,并且如果该处理程序的设计不能够做到这一点(取决于其内部结构),则它可能无法工作。在单线程应用程序中“并行”表示,第一个类实例尚未使用处理程序完成,然后第二个实例开始使用处理程序。在这种情况下,建议使用实例变量代替。
麻省理工学院

0

像下面的例子一样实现return语句!你应该很好。我希望它可以帮助某人..

class Example(object):
    def the_example(self):
        itsProblem = "problem"
        return itsProblem 


theExample = Example()
print theExample.the_example()

1
您应该修复代码缩进。该问题也有出色的答案,您的答案是这些答案的基本变形,而不是替代的解决方案...
HEADLESS_0NE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.