关于python:使用父函数中的子项覆盖的值

Using value overriden by child in a parent function

我定义了一个处理一般内容的基类,以及子类,它们接受的内容(对象类型)更具体。但是,当调用父类中定义的函数时,将使用父变量而不是子变量。如何让python在父函数中使用子变量?

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class BaseField(object):
    __accepted_types = (object,)

    def __init__(self, description=""):
        self.content = None
        self.description = description

    def set(self, content):
        if isinstance(content, self.__accepted_types):
            print(type(content), self.__accepted_types)
            print(type(self))
            self.__set(content)
        else:
            raise ValueError("wrong type")

    def __set(self, content):
        pass

class StringField(BaseField):
    __accepted_types = (basestring,)

    def __init__(self, description=""):
        super().__init__(description)
        print(self.__accepted_types)

if __name__ == '__main__':
    x = StringField("a test field")
    x.set(3)

我希望此代码引发一个ValueError(我正试图将一个int传递给一个只接受str的类),但是我得到了以下结果:

1
2
(<class 'str'>,)
<class 'int'> (<class 'object'>,) <class '__main__.StringField'>

注意,函数正确地返回它在"StringField"内,但使用"BaseField"值作为__accepted_types的值。如果我将__accepted_types声明为实例变量,则行为是相同的。


你成了名字错位的牺牲品;名字在班级里被弄脏,self.__accepted_typesget在set里被转换成_BaseField__accepted_types

把所有出现的__accepted_types都改成accepted_types,就可以了。

另外,如果您确实在使用python 3,那么basestring不存在,请使用str


作为另一个答案的后续,我强烈建议您观看Pycon2013的演讲,其中讨论了Python名称管理范式的用途和用法。

总之,对对象变量使用双下划线并不是保持它们"私有"的方法。事实上,python中的私有变量不是"一回事";当来自其他语言时,有效地使用python需要在这个和其他主题上进行思考。

名称管理的目的是防止父类和子类落入名称空间战争的陷阱,例如,某些子类将属性名用于与父类不同的目的。

如需进一步阅读,请参阅以下其他问题和答案:

带变量和方法的下划线与双下划线

对象名称前的单下划线和双下划线的含义是什么?