2

我之前在谷歌上搜索了一些与 Python 相关的问题,偶然发现了这个页面。作者做了如下的事情:

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

像这样“声明”变量有什么意义first?我以前从未见过这样做过,而且我一生都无法想到在为变量分配一些值之前创建变量是有益的情况。

上面的示例也可能看起来像这样:

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

...还是我错过了什么?

4

4 回答 4

6

作者使用的事实

first = str()

first = ''

self.first无论如何都表明,__init__这样做没有任何目的。

可能作者很困惑,认为python变量需要先声明-_-(查看链接时明显)

于 2013-05-29T10:29:08.163 回答
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': ''}
于 2013-05-29T10:33:22.847 回答
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.attror y.attr,Python 首先查找附加到实例本身的内容。但是,如果没有找到任何东西,它会“向上查找”以查看是否有其他东西定义了该属性。对于具有继承的类,这涉及通过“成员解析顺序”列表。在这种情况下,无需担心继承,但下一步是查看类本身。在这里,在 K2 中,类中有一个名为 的属性,attr这就是 y.attr 产生的。

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

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

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

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

请注意,更改 xattr不会影响 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.attrand z.attrare both really y.__class__.__dict__['attr']and z.__class__.__dict__['attr'],并且因为y.__class__and z.__class__are both K2,都在改变K2.attr变化。

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

于 2013-05-29T10:56:26.397 回答
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'

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

于 2013-05-29T10:49:14.513 回答