理解python类属性

时间:2013-07-09 18:03:58

标签: python python-2.7 python-3.x

我是编程新手并开始学习python。可能看起来很愚蠢的问题,所以请原谅我的无知。 请考虑以下代码片段:

class Test1:
    bar = 10    
    def display(self,foo):
        self.foo=foo
        print "foo : ",self.foo #80
    def display1(self):
        print "bar: ", self.bar #10
        print "again foo: ", self.foo #80

if __name__ == '__main__':
    test1 = Test1()
    test1.display(80)
    test1.display1()
    print test1.bar #10
    print test1.foo #80

我想了解使用foo和bar(wrt到我们定义它们的地方)之间的区别,因为在范围方面它们在所有地方都可以相互比较,只有区别在于一个是在函数内部和另一个是在Class内部,但它们都仍然是"实例"变量。 那么哪种做法很好?

另外,如果我稍微修改显示功能如下:

    def display(self,foo):
        self.foo=foo
        foo = foo
        print "self.foo : ",self.foo 
        print "foo : ",foo 

有人可以解释一下python是如何看到这一点的,因为这个self关键字在两个foo之间带来了什么区别/重要性。

3 个答案:

答案 0 :(得分:4)

bar是一个类属性,foo是一个实例属性。主要区别在于bar将可用于所有类实例,而foo仅在您在该实例上调用display时才可用于实例

>>> ins1 = Test1()

ins1.bar工作正常,因为它是一个类属性,并且由所有实例共享。

>>> ins1.bar
10

但你不能直接在这里访问foo,因为它尚未定义:

>>> ins1.foo
Traceback (most recent call last):
  File "<ipython-input-62-9495b4da308f>", line 1, in <module>
    ins1.foo
AttributeError: Test1 instance has no attribute 'foo'

>>> ins1.display(12)
foo :  12
>>> ins1.foo
12

如果要在创建实例时初始化某些实例属性,请将它们放在__init__方法中。

class A(object):
    bar =  10
    def __init__(self, foo):
        self.foo = foo   #this gets initialized when the instance is created
    def func(self, x):
        self.spam = x    #this will be available only when you call func() on the instance
...         
>>> a = A(10)
>>> a.bar
10
>>> a.foo
10
>>> a.spam
Traceback (most recent call last):
  File "<ipython-input-85-3b4ed07da1b4>", line 1, in <module>
    a.spam
AttributeError: 'A' object has no attribute 'spam'

>>> a.func(2)
>>> a.spam
2

答案 1 :(得分:3)

bar是一个类属性。由于Python中的类是对象,因此它们也可以具有属性。 bar只是碰巧住在Test对象上,而不是它的实例。

由于Python解析属性查找的方式,看起来test1具有bar属性,但它没有。

另一方面,

foo在调用test1后依赖实例display(80)。这意味着Test的不同实例可以在各自的foo属性中具有不同的值。

当然,您可以将类变量用作某种“共享默认值”,然后可以使用实例属性“覆盖”,但这可能会让人感到困惑。

第二个问题

def display(self,foo):
    self.foo=foo
    foo = foo
    print "self.foo : ",self.foo 
    print "foo : ",foo 

让我们只是弄清楚一个细节:self不是关键字,只是召唤第一个参数“self”,你也可以称之为“this”或“that”或“bar” “如果你喜欢,但我不建议这样做。

Python将传递对象,在该对象上调用该方法作为第一个参数。

def display(self,foo): 

这个foo是显示实例函数的第一个参数的名称。

    self.foo=foo

这将使用实例的名称“foo”设置属性,在该属性上调用display()作为第一个参数传递的值。使用您的示例test1.display(80)self将为test1foo80test1.foo将设置为80

    foo = foo

这一点都没有。它引用了第一个参数foo

接下来的两行再次引用实例变量foo和第一个参数foo

答案 2 :(得分:1)

就我个人而言,我不喜欢在__init__以外的方法中定义实例变量,或者在上面的示例中定义像bar这样的类变量。

再一次,就个人而言,我希望通过查看顶部来看到我班上的每个成员。无论是用作实例变量的类变量(我通常不做的事情)还是在__init__中定义的实例变量,都可以很容易地告诉我们在类中定义了什么和没有定义检查类定义的第一部分。

如果您不需要作为类成员访问变量(即,您只是在那里定义它以避免在self.variable = val方法中编写__init__,那么我会避开它如果你可能需要将它作为一个类变量来访问,那么在我的书中就可以使用bar来做你想做的事了。

这将是我写作课程的首选方式。

class Test1:

    def __init__(self):
        self.foo = None
        self.bar = 10

    def display(self,foo):
        self.foo=foo
        print "foo : ",self.foo #80

    def display1(self):
        print "bar: ", self.bar #10
        print "again foo: ", self.foo #80