开发者

Python base classes share attributes? [duplicate]

This question already has answers here: Python constructor and default value [duplicate] (4 answers) "Least Asto开发者_如何学运维nishment" and the Mutable Default Argument (32 answers) Closed 4 years ago.

Code in test.py:

class Base(object):
    def __init__(self, l=[]):
        self.l = l

    def add(self, num):
        self.l.append(num)

    def remove(self, num):
        self.l.remove(num)

class Derived(Base):
    def __init__(self, l=[]):
        super(Derived, self).__init__(l)

Python shell session:

Python 2.6.5 (r265:79063, Apr  1 2010, 05:22:20) 
[GCC 4.4.3 20100316 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> a = test.Derived()
>>> b = test.Derived()
>>> a.l
[]
>>> b.l
[]
>>> a.add(1)
>>> a.l
[1]
>>> b.l
[1]
>>> c = test.Derived()
>>> c.l
[1]

I was expecting "C++-like" behavior, in which each derived object contains its own instance of the base class. Is this still the case? Why does each object appear to share the same list instance?


You're making a common Python newcomer mistake.

See my answer here: How should I declare default values for instance variables in Python?

Briefly explained, Python interprets the class definitions only once. That means everything declared in the __init__() method is only created once. Or, in another words, your [] list default argument is only made once.

Then self.l = l assigns a reference to the same instance every time you create a new class, hence the behaviour you weren't expecting.

The Pythonic way is this (partial code):

def __init__(self, arg=None):
    if arg is None:
        arg = []
    self.arg = arg

Also, you should consider using a better naming convention than l, which is hard to read and might be mistaken as 1 or |.


This is called the mutable default argument bug that is commonly made by people new to Python. When you give a mutable as a default argument, the same object gets used across instances when the default argument is required to be used. The get a better understand check the Important warning section in http://docs.python.org/tutorial/controlflow.html#default-argument-values

In your code, the instance a used the mutable default argument (a empty list object) in it's init call and when you created the instance of b, which in turn called Base's init method, again used the very same object that a used in it's init. On simpler words a.l and b.l point to the same list object.

A very similar discussion - "Least Astonishment" and the Mutable Default Argument

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜