出于易读性的目的,我希望有一个自定义类,其行为与dict完全相同(但带有有意义的类型,而不是更通用的dict类型):
class Derivatives(dict):
"Dictionary that represents the derivatives."
现在,有没有办法以不涉及副本的方式构建此类的新对象?天真的用法
derivs = Derivatives({var: 1}) # var is a Python object
实际上,创建了作为参数传递的字典的副本,出于效率原因,我想避免这样做。
我试图绕过副本,但是在CPython中无法更改dict的类:
class Derivatives(dict):
def __new__(cls, init_dict):
init_dict.__class__ = cls # Fails with __class__ assignment: only for heap types
return init_dict
我希望能够为字典提供明确的类名,程序操作和是构建此类字典的有效方法(而不是强制复制Python字典) 。这在Python中有效吗?
PS:用例可能是单键Derivatives
的100,000次创建,其中键是变量(不是字符串,因此没有关键字初始化)。这实际上并不慢,所以“效率原因”在这里意味着更像“优雅”:理想情况下,当不需要副本时,不需要浪费时间复制。所以,在这个特殊情况下,问题更多的是关于Python在这里带来的优雅/清晰度,而不是关于运行速度。
答案 0 :(得分:1)
TL; 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
并在Derivatives
类中插入值。这是不可避免的,除非您能够以某种方式将类的内部哈希表设置为dict
的内部哈希表。在纯python中无法做到这一点,因为dict类是用C实现的(如上所述)。
请注意,其他人建议使用生成器。这似乎也是一个好主意 - 比如你是从文件中读取衍生物还是用简单的公式生成它们。它会避免首先创建dict
对象。但是,如果生成器只是list
s(或任何其他可以包含一组值的数据结构)的包装器,效率将不会有明显的提高。
您最好的选择是坚持使用原始方法。生成器很棒,但它们不能有效地表示一组具有一系列价值(在您的场景中可能就是这种情况)。在C中做它也不值得。
编辑:毕竟可能值得在C中做到这一点!
我对Python C API的细节不是太大,但考虑在C中定义一个类,例如DerivativesBase
(派生自dict
)。您所做的只是在C中为__init__
定义一个DerivativesBase
函数,该函数将dict
作为参数,并将哈希表指针从dict
复制到您的DerivativesBase
中对象。然后,在python中,您的Derivatives
类派生自DerivativesBase
并实现大部分功能。
答案 1 :(得分:1)
通过继承dict
,你有三种构造函数参数的可能性:( baring {}
literal)
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
这意味着,为了实例化您的实例,必须执行以下操作之一:
D(x=1)
传递,然后将其打包到中间字典中。创建普通字典并将其作为mapping
传递。
传递可重复的(键,值)对。
因此,在所有这三种情况下,您都需要创建中间对象以满足dict
构造函数。
单个对的第三个选项看起来像D(((var,1),))
,为了便于阅读,我强烈推荐这个选项。
因此,如果您希望您的类继承自字典,那么使用Derivatives({var: 1})
是您最有效和最易读的选项。
作为个人记录,如果你有成千上万的单对词典,我不确定dict
设置如何是最好的,你可能只是重新考虑你班级的基础。 / p>