为什么在Python中'声明'变量?

时间:2013-05-29 10:27:32

标签: python variable-declaration

我之前在Google上搜索了一些与Python相关的问题,偶然发现了this页面。作者做了类似以下的事情:

class TestClass(object):
    first = str()
    def __init__(self):
        self.first = "Hello"

像这样“声明”变量first有什么意义?我以前从未见过这样做过,而且我不能为我的生活想到这样一种情况,即在为变量赋值之前创建变量是有益的。

以上示例可能看起来像这样:

class TestClass(object):
    def __init__(self, first="Hello"):
        self.first = first

......或者我错过了什么?

4 个答案:

答案 0 :(得分:6)

作者使用

这一事实
first = str()

而不是

first = ''
无论如何,

会在self.first中设置__init__,但这样做没有任何意义。

也许作者感到困惑并且认为python变量需要首先声明 - (在查看链接时很明显)

答案 1 :(得分:3)

str()等于""

>>> str()
''

我认为作者希望显示实例属性覆盖具有相同名称的类属性。所以在执行时

test = testclass()  
print test.__dict__  

你会得到:

{'second': 'weird', 'third': 'test', 'first': 'Some'}

不是

{'second': '', 'third': '', 'first': ''}

但是

print testclass.__dict__

将打印类属性:

{'__module__': '__main__', 'third': '', 'second': '', '__doc__': None, '__init__': <function __init__ at 0xb5fed6bc>, 'first': ''}

答案 2 :(得分:3)

这不是声明,这是对类中的变量的赋值,而不是实例中的变量。

考虑以下输出:

>>> class K1(object):
...     def __init__(self):
...         self.attr = 'value'
... 
>>> x = K1()
>>> x.__dict__
{'attr': 'value'}
>>> class K2(object):
...     attr = 'value'
...     def __init__(self):
...         self.another = 'value2'
... 
>>> y = K2()
>>> y.__dict__
{'another': 'value2'}

此处x是类K1的实例,并且具有名为attr的属性,y是类K2的实例,并且具有名为another的不同属性。但是:

>>> y.attr
'value'

那是从哪里来的?它来自班级:

>>> y.__class__.__dict__
dict_proxy({'__module__': '__main__', 'attr': 'value',
'__dict__': <attribute '__dict__' of 'K2' objects>,
'__weakref__': <attribute '__weakref__' of 'K2' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b9b0>})

那有点乱,但你可以看到坐在那里的attr。如果你看x.__class__.__dict__,那就没有attr

>>> x.__class__.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'K1' objects>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'K1' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b938>})

当您获得某个实例的属性时,如x.attry.attr,Python首先会查找附加到实例本身的内容。但是,如果找不到任何东西,它会“向上看”以查看是否有其他东西定义了该属性。对于具有继承的类,涉及通过“成员解析顺序”列表。在这种情况下,不需要担心继承,但下一步是查看类本身。在K2中,名为attr的类中有一个属性,这就是y.attr产生的属性。

您可以更改类属性以更改y.attr中显示的内容:

>>> K2.attr = 'newvalue'
>>> y.attr
'newvalue'

事实上,如果你创建另一个K2()实例,它也会获取新值:

>>> z = K2()
>>> z.attr
'newvalue'

请注意,更改x的attr不会影响K1()的新实例:

>>> w = K1()
>>> w.attr = 'private to w'
>>> w.attr
'private to w'
>>> x.attr
'value'

那是因为w.attr真的是w.__dict__['attr'],而x.attr确实是x.__dict__['attr']。另一方面,y.attrz.attr都是y.__class__.__dict__['attr']z.__class__.__dict__['attr'],因为y.__class__z.__class__都是K2 },更改K2.attr会同时更改。

(我不确定编写原始问题中引用的页面的人是否实现了这一切。创建一个类级属性然后创建一个具有相同名称的实例级属性是没有意义的。)

答案 3 :(得分:1)

这两个例子之间确实存在一点差异:

class TestClass(object):
    first = 'foo'
    def __init__(self):
        self.first = "Hello"

print(TestClass.first)

输出:

foo

但是:

class TestClass(object):
    def __init__(self, first="Hello"):
        self.first = "Hello"

print(TestClass.first)

输出:

Traceback (most recent call last):
  File "C:\Users\...\Desktop\test.py", line 5, in <module>
    print(TestClass.first)
AttributeError: type object 'TestClass' has no attribute 'first'

注意:但这并不意味着作者的代码有意义。只想指出差异。