Python构造函数和默认值

Her*_*ery 107 python constructor default-value

不知何故,在下面的Node类中,wordList和adjacencyList变量在Node的所有实例之间共享.

>>> class Node:
...     def __init__(self, wordList = [], adjacencyList = []):
...         self.wordList = wordList
...         self.adjacencyList = adjacencyList
... 
>>> a = Node()
>>> b = Node()
>>> a.wordList.append("hahaha")
>>> b.wordList
['hahaha']
>>> b.adjacencyList.append("hoho")
>>> a.adjacencyList
['hoho']
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以继续使用默认值(在这种情况下为空列表)的构造函数参数,但要让a和b都有自己的wordList和adjacencyList变量?

我正在使用python 3.1.2.

Mic*_*ber 130

可变默认参数通常不会执行您想要的操作.相反,试试这个:

class Node:
     def __init__(self, wordList=None, adjacencyList=None):
        if wordList is None:
            self.wordList = []
        else:
             self.wordList = wordList 
        if adjacencyList is None:
            self.adjacencyList = []
        else:
             self.adjacencyList = adjacencyList 
Run Code Online (Sandbox Code Playgroud)

  • 这些也可以是单行:`self.wordList = wordList如果wordList不是None else []`,或者稍微不那么安全,`self.wordList = wordList或[]`. (26认同)
  • @markdsievers除了'None`之外的许多东西评价为'False`(例如`False`,`0`,````,`{}`,`()`,指定`__nonzero __()`的对象.前者是特定的:`None`是唯一触发默认为`[]`的特殊对象.后者将用`[]`替换任何false-y对象. (5认同)
  • 那么,这是一个错误吗?这种行为非常违反直觉. (5认同)
  • Michael J. Barber的贡献是正确的 - 但没有提供任何解释.此行为的原因是默认参数绑定在函数定义,而不是运行时.请参阅http://stackoverflow.com/questions/1132941/least-astonishment-in-python-which-scope-is-the-mutable-default-argument-in (5认同)
  • 这被认为是Pythonic方式,但我更喜欢krousey的方式,因为"特殊情况不够特别". (2认同)
  • @sharshofski:这是一个糟糕的设计决策,我不知道有任何其他语言可以处理这样的默认值,但它并没有被正式视为错误。 (2认同)

aar*_*ing 31

让我们来说明这里发生了什么:

Python 3.1.2 (r312:79147, Sep 27 2010, 09:45:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     def __init__(self, x=[]):
...         x.append(1)
... 
>>> Foo.__init__.__defaults__
([],)
>>> f = Foo()
>>> Foo.__init__.__defaults__
([1],)
>>> f2 = Foo()
>>> Foo.__init__.__defaults__
([1, 1],)
Run Code Online (Sandbox Code Playgroud)

您可以看到默认参数存储在元组中,元组是相关函数的属性.这实际上与所讨论的类无关,适用于任何功能.在python 2中,属性将是func.func_defaults.

正如其他海报所指出的那样,您可能希望将其None用作哨兵值,并为每个实例提供自己的列表.


kro*_*sey 17

我会尝试:

self.wordList = list(wordList)
Run Code Online (Sandbox Code Playgroud)

强制它制作副本而不是引用同一个对象.


Sha*_*bus 17

class Node:
    def __init__(self, wordList=None adjacencyList=None):
        self.wordList = wordList or []
        self.adjacencyList = adjacencyList or []
Run Code Online (Sandbox Code Playgroud)