【发布时间】:2022-01-24 08:49:32
【问题描述】:
问题
嗨。请考虑此代码
import numpy as np
class MappingFoo:
bar = {"a": 1}
__len__ = bar.__len__
__iter__ = bar.__iter__
__getitem__ = bar.__getitem__
foo = MappingFoo()
print(np.array([foo.bar])) # [{'a': 1}] (np array with dtype object)
print(np.array([foo])) # [['a']] (np array with dtype str)
注意:MappingFoo 完全实现了继承并成为 collections.abc.Mapping 所需的所有 3 个魔术方法。
这是我的观察:
- numpy 将
MappingFoo视为列表/可迭代对象。 - 如果您删除
MappingFoo的 3 个魔术方法中的任何一个,np.array([foo])也将返回一个对象数组,就像第一个np.array(...)调用一样。 -
MappingFoo是否继承自collections.abc.Mapping没有区别。
这是我的问题:
- 在使用
numpy.array(...)创建数组时,numpy 如何决定应该扩展/迭代哪些对象? - 如果我不遍历我的
MappingFoo对象并将它们作为对象存储在数组中,我该如何停止?备注:在我的真实示例中,我事先并不知道输入的类型。因此,我想使用np.array(...)来创建数组,而不是依赖np.empty(...)然后将其填充到循环或其他需要显式 dtype 的解决方法中。
说明问题 2 的一段代码
俗话说:一段代码值一千字。所以这里用代码重新表述问题 2。
from random import (
randint,
random,
)
def generate_input():
"""Generate a non-deterministic list as input for np.array.
Generate a list or list of lists or 3-times nested list with either
* only integers
* a mixture of integers and MappingFoo objects
* only MappingFoo objects
"""
def generator(shape_, foo_it_all):
if len(shape_) == 1:
return [randint(0, 255)
if not foo_it_all and random() < .99
else MappingFoo()
for _ in range(shape_[0])]
else:
return [generator(shape_[1:], foo_it_all)
for _ in range(shape_[0])]
dim = randint(1, 3)
shape = tuple(randint(1, 10) for _ in range(dim))
return shape, generator(shape, random() > .5)
shape, input_ = generate_input()
array = np.array(input_)
print(array)
print(array.dtype)
print(shape)
assert array.shape == shape
如何在不更改generate_input 或使用shape 的情况下使断言每次都通过?更改 MappingFoo 就可以了(当然不会删除功能)。最后,array 应该具有保持序列中对象所需的最小 dtype。
【问题讨论】:
-
您似乎找到了
np.array的控制限制。显然,使用这些方法,输入有资格作为“任何(嵌套)序列”。正如我(和其他人)所展示的,empty/fill是制作具有指定形状的对象 dtype 数组的唯一可靠方法。否则,您将受到np.array's的摆布,尝试创建一个多维(数字)数组。 -
"
MappingFoo完全实现了成为collections.abc.Mapping所需的所有 3 种魔术方法。"请注意,它没有。它实现了从collections.abc.Mapping继承时所需的所有抽象方法。Mapping还必须提供__contains__、keys、items、values、get、__eq__和__ne__。即使那样,Mapping也不是结构性的——仅仅提供方法还不足以满足isinstance(foo, Mapping);该类必须继承自register和Mapping。 -
确实如此。我说的很糟糕。我的意思是:它实现了
collections.abc.Mapping所需的方法。当然它不会是它的子类,除非它是它的子类。如果该类没有执行此操作的元类(或通过其他外部方式),其余的魔术方法将不会神奇地出现。我将问题编辑得更准确。谢谢。 -
实际上有各种在结构上起作用的 ABC——例如
Hashable、Container或Generator——这样实现“他们的”方法就足以创建一个子类,即使没有继承。不过,Mapping不是其中之一,它的三个抽象特殊方法对于Mapping并不特别——例如,list也有它们。
标签: python python-3.x numpy