python 子类化 dict:应该调用 dict.__init__() 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2033150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:37:56  来源:igfitidea点击:

Subclassing dict: should dict.__init__() be called?

pythonsubclassdictionaryinit

提问by Eric O Lebigot

Here is a twofold question, with a theoretical part, and a practical one:

这是一个双重问题,一个是理论部分,一个是实际问题:

When subclassing dict:

当子类化 dict 时:

class ImageDB(dict):
    def __init__(self, directory):
        dict.__init__(self)  # Necessary?? 
        ...

should dict.__init__(self)be called, just as a "safety" measure (e.g., in case there are some non-trivial implementation details that matter)? is there a risk that the code break with a future version of Python if dict.__init__()is notcalled? I'm looking for a fundamental reason of doing one thing or the other, here (practically, calling dict.__init__()is safe).

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

My guess is that when ImageDB.__init__(self, directory)is called, self is already a new empty dict object, and that there is therefore no need to call dict.__init__(I do want the dict to be empty, at first). Is this correct?

我的猜测是,当ImageDB.__init__(self, directory)被调用时,self 已经是一个新的空 dict 对象,因此不需要调用dict.__init__(我确实希望 dict 是空的,一开始)。这个对吗?

Edit:

编辑

The more practical question behind the fundamental question above is the following. I was thinking of subclassing dict because I would use the db[…] syntax quite often (instead of doing db.contents[…] all the time); the object's only data (attribute) is indeed really a dict. I want to add a few methods to the database (such as get_image_by_name(), or get_image_by_code(), for instance), and only override the __init__(), because the image database is defined by the directory that contains it.

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

In summary, the (practical) question could be: what is a good implementation for something that behaves like a dictionary, except that its initialization is different (it only takes a directory name), and that it has additional methods?

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

"Factories" were mentioned in many answers. So I guess it all boils down to: do you subclass dict, override __init__()and add methods, or do you write a (factory) function that returns a dict, to which you add methods? I'm inclined to prefer the first solution, because the factory function returns an object whose type does not indicate that it has additional semantics and methods, but what do you think?

许多答案中都提到了“工厂”。所以我想这一切都归结为:你是对 dict 进行子类化、覆盖__init__()和添加方法,还是编写一个返回 dict 的(工厂)函数,然后向其中添加方法?我更倾向于第一种解决方案,因为工厂函数返回一个对象,其类型并不表明它具有额外的语义和方法,但你怎么看?

Edit 2:

编辑2

I gather from everybody's answer that it is not a good idea to subclass dict when the new class "is not a dictionary", and in particular when its __init__method cannot take the same arguments as dict's __init__(which is the case in the "practical question" above). In other words, if I understand correctly, the consensus seems to be: when you subclass, all methods (including initialization) must have the same signature as the base class methods. This allows isinstance(subclass_instance, dict) to guarantee that subclass_instance.__init__()can be used like dict.__init__(), for instance.

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

Another practical question then pops up: how should a class which is just like dict, except for its initialization method, be implemented? without subclassing? this would require some bothersome boilerplate code, no?

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

采纳答案by Alan Franzoni

You should probably call dict.__init__(self)when subclassing; in fact, you don't know what's happening precisely in dict (since it's a builtin), and that might vary across versions and implementations. Not calling it may result in improper behaviour, since you can't know where dict is holding its internal data structures.

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

By the way, you didn't tell us what you wantto do; if you want a class with dict (mapping) behaviour, and you don't really need a dict (e.g. there's no code doing isinstance(x, dict)anywhere in your software, as it should be), you're probably better off at using UserDict.UserDictor UserDict.DictMixinif you're on python <= 2.5, or collections.MutableMappingif you're on python >= 2.6 . Those will provide your class with an excellent dict behaviour.

顺便说一句,你没有告诉我们你想做什么;如果你想用字典(映射)行为的一类,而你并不真正需要的字典(例如,有没有做的代码isinstance(x, dict)软件中的任何地方,因为它应该是),你可能会更好过是在使用UserDict.UserDictUserDict.DictMixin如果你”在 python <= 2.5 上,或者collections.MutableMapping如果你在 python >= 2.6 上。这些将为您的班级提供出色的 dict 行为。

EDIT: I read in another comment that you're not overriding any of dict's method! Then there's no point in subclassing at all, don't do it.

编辑:我在另一条评论中读到你没有覆盖任何 dict 的方法!那么子类化根本没有意义,不要这样做。

def createImageDb(directory):
    d = {}
    # do something to fill in the dict
    return d

EDIT 2: you want to inherit from dict to add new methods, but you don't need to override any. Than a good choice might be:

编辑 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

By the way: what methods are you adding? Are you sure you're creating a good abstraction? Maybe you'd better use a class which defines the methods you need and use a "normal" dict internally to it.

顺便说一句:你要添加什么方法?你确定你正在创建一个好的抽象?也许你最好使用一个定义你需要的方法的类,并在内部使用一个“正常”的字典。

Factory func: http://en.wikipedia.org/wiki/Factory_method_pattern

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

It's simply a way of delegating the construction of an instance to a function instead of overriding/changing its constructors.

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

回答by Anurag Uniyal

You should generally call base class' __init__so why make an exception here?

您通常应该调用基类',__init__那么为什么要在这里例外?

Either do not override __init__or if you need to override __init__call base class __init__, If you worry about arguments just pass *args, **kwargs or nothing if you want empty dict e.g.

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

class MyDict(dict):
    def __init__(self, *args, **kwargs ):
        myparam = kwargs.pop('myparam', '')
        dict.__init__(self, *args, **kwargs )

We shouldn't assume what baseclass is doing or not doing, it is wrong not to call base class __init__

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

回答by denis

Beware of pickling when subclassing dict; this for example needs __getnewargs__ in 2.7, and maybe __getstate__ __setstate__ in older versions. (I have no idea why.)

子类化 dict 时要小心酸洗;例如,这在 2.7 中需要 __getnewargs__,在旧版本中可能需要 __getstate__ __setstate__。(我不知道为什么。)

class Dotdict( dict ):
    """ d.key == d["key"] """

    def __init__(self, *args, **kwargs):
        dict.__init__( self, *args, **kwargs )
        self.__dict__ = self

    def __getnewargs__(self):  # for cPickle.dump( d, file, protocol=-1)
        return tuple(self)

回答by unutbu

PEP 372deals with adding an ordered dict to the collections module.

PEP 372处理向集合模块添加有序字典。

It warns that "subclassing dict is a non-trivial task and many implementations don't override all the methods properly which can lead to unexpected results."

它警告说“子类化 dict 是一项重要的任务,许多实现没有正确覆盖所有方法,这可能会导致意外结果。”

The proposed (and accepted) patchto python3.1 uses an __init__that looks like this:

提议(并接受)的python3.1补丁使用__init__如下所示:

+class OrderedDict(dict, MutableMapping):
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        if not hasattr(self, '_keys'):
+            self._keys = []
+        self.update(*args, **kwds)

Based on this, it looks like dict.__init__()does not need to be called.

基于此,看起来dict.__init__()不需要调用。

Edit:If you are not overriding or extending any of dict's methods, then, I agree with Alan Franzoni: use a dict factory rather than subclassing:

编辑:如果您没有覆盖或扩展任何dict方法,那么,我同意 Alan Franzoni:使用 dict 工厂而不是子类化:

def makeImageDB(*args,**kwargs):
   d = {}
   # modify d
   return d

回答by prosti

If you plan to subclass something like dictbase type you may also consider the UserDictfrom collections. UserDictis designed to be subclassed.

如果您打算子类化dict基类型之类的东西,您还可以考虑UserDictfrom 集合。UserDict被设计为子类。