子类化dict:应该调用dict .__ init __()吗?

Eri*_*got 31 python dictionary subclass init

这是一个双重问题,具有理论部分和实践部分:

子类化dict时:

class ImageDB(dict):
    def __init__(self, directory):
        dict.__init__(self)  # Necessary?? 
        ...
Run Code Online (Sandbox Code Playgroud)

应该dict.__init__(self)被称为"安全"措施(例如,如果有一些重要的非平凡实施细节)?有一个风险,即与Python的未来版本的代码休息,如果dict.__init__()叫?我正在寻找做一件事或另一件事的根本原因,这里(实际上,呼叫dict.__init__()是安全的).

我的猜测是,当ImageDB.__init__(self, directory)调用时,self已经是一个新的空dict对象,因此无需调用dict.__init__(我确实希望dict为空,首先).它是否正确?

编辑:

以上基本问题背后更实际的问题如下.我在考虑继承dict,因为我会经常使用db [...]语法(而不是一直使用db.contents [...]); 对象的唯一数据(属性)确实是一个字典.我想向数据库添加一些方法(例如get_image_by_name(),或者get_image_by_code(),例如),并且只覆盖__init__(),因为图像数据库是由包含它的目录定义的.

总之,(实际)问题可能是:对于行为类似于字典的东西,什么是良好的实现,除了它的初始化是不同的(它只需要一个目录名),并且它有其他方法?

许多答案都提到了"工厂".所以我想这一切归结为:你是否继承dict,覆盖__init__()和添加方法,还是你写了一个返回dict的(工厂)函数,你要添加方法?我更倾向于选择第一个解决方案,因为工厂函数返回一个对象,其类型并不表示它有其他语义和方法,但你怎么看?

编辑2:

我从每个人的回答中得知,当新类"不是字典"时,将dict子类化并不是一个好主意,特别是当它的__init__方法不能采用与dict相同的参数时__init__(在"实际问题"中就是这种情况)以上).换句话说,如果我理解正确,那么共识似乎是:当您进行子类化时,所有方法(包括初始化)必须与基类方法具有相同的签名.这允许isinstance(subclass_instance,dict)保证subclass_instance.__init__()可以像dict.__init__()例如一样使用.

然后弹出另一个实际问题:除了初始化方法之外,应该如何实现类似dict的类?没有子类?这需要一些麻烦的样板代码,不是吗?

Ala*_*oni 15

你应该dict.__init__(self)在子类化时调用; 事实上,你不知道dict中究竟发生了什么(因为它是内置的),并且可能因版本和实现而异.不调用它可能会导致不正确的行为,因为您无法知道dict在哪里持有其内部数据结构.

顺便说一句,你没告诉我们你想做什么; 如果你想要一个带有dict(映射)行为的类,并且你真的不需要一个dict(例如isinstance(x, dict),你的软件中没有代码可以执行任何代码),你可能会更好地使用UserDict.UserDict或者UserDict.DictMixin如果你'在python <= 2.5上,或者collections.MutableMapping如果你在python> = 2.6上.这些将为您的班级提供优秀的词典行为.

编辑:我在另一条评论中读到,你没有凌驾于任何dict的方法!然后在子类化中没有任何意义,不要这样做.

def createImageDb(directory):
    d = {}
    # do something to fill in the dict
    return d
Run Code Online (Sandbox Code Playgroud)

编辑2:你想从dict继承添加新方法,但你不需要覆盖任何方法.比一个好的选择可能是:

class MyContainer(dict):
    def newmethod1(self, args):
        pass

    def newmethod2(self, args2):
        pass


def createImageDb(directory):
    d = MyContainer()
    # fill the container
    return d
Run Code Online (Sandbox Code Playgroud)

顺便问一下:你在添加什么方法?你确定你正在创造一个好的抽象吗?也许你最好使用一个定义你需要的方法的类,并在内部使用一个"普通"的dict.

工厂功能:http: //en.wikipedia.org/wiki/Factory_method_pattern

它只是一种将实例的构造委托给函数而不是覆盖/更改其构造函数的方法.

  • +1:当不需要子类时进行子类化是一个坏主意,工厂要好得多. (2认同)

Anu*_*yal 12

你通常应该调用基类' __init__为什么在这里做一个例外?

要么不要覆盖,__init__要么你需要覆盖__init__ 调用基类__init__,如果你担心参数只是传递*args,**kwargs或者如果你想要空的dict就没有例子,例如

class MyDict(dict):
    def __init__(self, *args, **kwargs ):
        myparam = kwargs.pop('myparam', '')
        dict.__init__(self, *args, **kwargs )
Run Code Online (Sandbox Code Playgroud)

我们不应该假设基类正在做什么或不做什么,不调用基类是错误的 __init__