__init__方法在没有传递时获取值

时间:2017-01-17 08:25:03

标签: python default init

我有一个班级TextBuffer。它具有__init__函数,可用于传递TextBuffer内容的初始值。如果没有传递任何值,那么它应该使用空列表作为默认值。

该类有一个方法添加,以便向TextBuffer添加文字:

a = TextBuffer()
a += "TEXT"

出于某种原因,调用不带参数的__init__方法不会将[]的默认值用于lst,而是先前为TextBuffer的另一个实例添加的值,不在__init__电话

a = TextBuffer()
a += "BUFFER A"
b = TextBuffer()  ### lst in the __init__ call has the value of ["BUFFER A"]
b += "BUFFER B"

我不知道为什么会这样。也许我在__add__方法中做错了什么?

请考虑完整的示例代码:

import pprint

### Two functions for byte/string conversion in Python3
def b(x):
    if ( type(x) == type(b'')):
        return x
    else:
        return x.encode(encoding='UTF-8')
def s(x):
    if ( type(x) == type(b'') ):
        return x.decode(encoding='UTF-8')
    else:
        return x


class TextBuffer():
    def __init__( self, lst = [], maxlines = None ):
        self.content = []
        if ( type(lst) == type([])):
            if (len(lst) > 0):
                print("INIT got a nonempty lst value:")
                pprint.pprint(lst)
                print("------------------------------")
            self.content = lst


    def __getitem__( self, i ):
        try:
            return self.content[i]
        except IndexError:
            return None

    def __iter__( self ):
        for line in self.content:
            yield line

    def __contains__( self, item ):
        return item in self.content

    def __len__( self ):
        return len(self.content)

    def __add__( self, item ):
        self.content.append(item)
        return self

    def __radd__( self, item ):
        return self.__add__(item)

    def __repr__( self ):
        result = ""
        for line in self.content:
            if ( type(line) == type(b"") ):
                result+=s(line)
            else:
                result+=line
        return result

    def __str__( self ):
        return repr(self)

    def __unicode__( self ):
        return repr(self.content)

### TextBuffer INIT with empty list creates an empty textbuffer
a = TextBuffer(lst=[])
print("a = TextBuffer(lst=[])")

a += "BUFFER A"


### TextBuffer INIT with empty list creates an empty textbuffer
b = TextBuffer(lst=[])
print("b = TextBuffer(lst=[])")

b += "BUFFER B"

print("Content of TextBuffer a:")
print(a)
print("Content of TextBuffer b:")
print(b)

print("-------------------------")

### TextBuffer INIT without any parameters should use default value for lst of []
### So an empty list. Should be the same as TextBuffer(lst=[])
a = TextBuffer()
print("a = TextBuffer()")

a += "BUFFER A"

### TextBuffer INIT without any parameters should use default value for lst of []
### So an empty list. Should be the same as TextBuffer(lst=[])
### But now, the value of lst is not [], it is the string added to TextBuffer 'a': ['BUFFER A']
b = TextBuffer()
print("b = TextBuffer()")

b += "BUFFER B"

print("Content of TextBuffer a:")
print(a)
print("Content of TextBuffer b:")
print(b)

1 个答案:

答案 0 :(得分:2)

在这种情况下,您无法使用lst = [] 作为默认参数,因为Python会在内存中生成一个列表,并且每次引用时都会传递构造函数的相同对象(列表)。这意味着您的两个对象共享相同的lst,因此一个对象所做的修改会反映在另一个对象中,反之亦然。

您可以使用以下技巧:

def __init__( self, lst = None, maxlines = None ):
    if lst is None:
        lst = []
    #... (remainder of the constructor)

因为在这里你迫使Python 构建一个新列表。显然你可以使用另一个值None;但我想你的情况就足够了。

一般来说,可变对象作为默认值提交,总是使用不可变对象。但是,正如@hiroprotagonist描述了需要这种行为的情况(如记忆),但我建议对这些行为要非常小心。