Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 自定义类是dict,但初始化时没有dict副本?_Python_Dictionary_Inheritance - Fatal编程技术网

Python 自定义类是dict,但初始化时没有dict副本?

Python 自定义类是dict,但初始化时没有dict副本?,python,dictionary,inheritance,Python,Dictionary,Inheritance,出于易读性的目的,我希望有一个行为与dict完全相同的自定义类(但携带有意义的类型,而不是更一般的dict类型): 现在,有没有一种方法可以以不涉及副本的方式构建此类的新对象?天真的用法 derivs = Derivatives({var: 1}) # var is a Python object 事实上,我创建了作为参数传递的字典的副本,出于效率原因,我希望避免这样做 我试图绕过副本,但无法更改dict的类,在CPython中: class Derivatives(dict): d

出于易读性的目的,我希望有一个行为与dict完全相同的自定义类(但携带有意义的类型,而不是更一般的dict类型):

现在,有没有一种方法可以以不涉及副本的方式构建此类的新对象?天真的用法

derivs = Derivatives({var: 1})  # var is a Python object
事实上,我创建了作为参数传递的字典的副本,出于效率原因,我希望避免这样做

我试图绕过副本,但无法更改dict的类,在CPython中:

class Derivatives(dict):
    def __new__(cls, init_dict):
        init_dict.__class__ = cls  # Fails with __class__ assignment: only for heap types
        return init_dict
我希望能够为程序操作的字典提供一个显式的类名,并且能够高效地构建这样的字典(而不是被迫复制Python dict)。这在Python中有效吗


PS:用例可能是100000个单键
衍生工具的创建,其中键是一个变量(不是字符串,因此没有关键字初始化)。这实际上并不慢,所以这里的“效率原因”更像是“优雅”:理想情况下,当不需要拷贝时,不需要浪费时间来拷贝。因此,在这种情况下,问题更多的是Python能带来的优雅/清晰,而不是运行速度;DR:除非用C语言,否则没有通用的方法

长答覆:
dict
类是用C实现的。因此,除非使用C,否则无法访问它的内部属性——最重要的是,它是内部哈希表

在C语言中,您可以简单地将表示哈希表的指针复制到对象中,而无需迭代
dict
(键、值)对并将它们插入到对象中。(当然,它比这要复杂一些。请注意,我省略了内存管理细节)

详细回答:

我不知道你为什么关心效率

Python将参数作为引用传递。除非你明确告诉它,否则它很少复制每一份

我在评论中看到,不能使用命名参数,因为键是实际的Python对象。这让我明白,您担心复制
dict
键(可能还有值)。但是,即使是字典键也不会被复制,而是通过引用传递!考虑这个代码:

class Test:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __hash__(self):
        return self.x

t = Test(1, 2)
print(t.y) # prints 2
d = {t: 1}
print(d[t]) # prints 1
keys = list(d.keys())
keys[0].y = 10
print(t.y)  # prints 10! No copying was made when inserting object into dictionary.
因此,唯一剩下的关注点是遍历
dict
并在
派生类中插入值。这是不可避免的,除非您能够以某种方式将类的内部哈希表设置为
dict
的内部哈希表。在纯python中无法做到这一点,因为dict类是用C实现的(如上所述)

请注意,其他人建议使用发电机。这似乎也是一个好主意——比如说,如果你从一个文件中读取导数,或者如果你用一个简单的公式生成它们。它将首先避免创建
dict
对象。但是,如果生成器只是
list
s(或任何其他可以包含任意值集的数据结构)的包装,那么效率将不会有明显的提高

你最好还是坚持你原来的方法。生成器很好,但它们不能有效地表示任意值集(在您的场景中可能就是这种情况)。在C语言中这样做也不值得

编辑:毕竟,用C语言做这件事是值得的

我对Python C API的细节不太大,但是考虑在C中定义一个类,例如,代码> DerivativesBase < /代码>(从<代码> DICT派生)。您只需在C中为

DerivativeBase
定义一个
\uuuu init\uuuu
函数,该函数将
dict
作为参数,并将哈希表指针从
dict
复制到
DerivativeBase
对象中。然后,在python中,您的
派生类派生自
developerativesbase
,并实现了大部分功能。

通过继承,为构造函数参数提供了三种可能性:(突出
{}
文本)

这意味着,为了实例化实例,您必须执行以下操作之一:

  • 将变量作为关键字
    D(x=1)
    传递,然后将其打包到中间字典中
  • 创建一个普通字典并将其作为映射传递

  • 传递(键、值)对的可数

  • 因此,在这三种情况下,您都需要创建中间对象来满足
    dict
    构造函数

    对于单个对,第三个选项看起来像
    D((var,1),)
    ,为了可读性,我强烈建议不要使用它

    因此,如果希望类从字典继承,那么使用
    派生({var:1})
    是最有效、最可读的选项


    作为个人注意事项,如果您将拥有数千本单对词典,我不确定
    dict
    设置首先是如何最好,您可以重新考虑您的课程基础。

    为什么不只是
    derivs=Derivatives(x=1)
    ?对于普通字典(
    dict({'x':1})
    ),同样的复制行为也会发生,不清楚您为什么会有其他期望。这一点很好,但我不能,因为键实际上是Python对象。我将更新这个示例。然后不,没有办法提供您自己的文本。如果你不需要它成为一本字典,你可以让它包含一本字典,然后通过
    \uu getitem\uuuu
    等方式公开它。这个答案,以及关于为什么会这样的解释/指针,将是我可以接受的答案。:)另一点:我没有想到
    派生词({…})
    会复制任何少于
    dict({…})
    (这是我所指的“幼稚用法”),我只是在寻找一种避免复制的方法(这是
    class Test:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __hash__(self):
            return self.x
    
    t = Test(1, 2)
    print(t.y) # prints 2
    d = {t: 1}
    print(d[t]) # prints 1
    keys = list(d.keys())
    keys[0].y = 10
    print(t.y)  # prints 10! No copying was made when inserting object into dictionary.
    
    class dict(**kwarg)
    class dict(mapping, **kwarg)
    class dict(iterable, **kwarg)