__new__ 不合理地创建生成器

__new__ irrationally creates generator

我有一个 class 处理数组并根据类型用不同的 class 包装它或制作一个生成器

Coat class 决定如何处理参数

涂层是核心class

class Coat:
    def __new__(cls, array, dtype=np.float32):

        if isinstance(array, np.ndarray):
            print('Condition 1')
            template = dtype(Coating(array.shape) * 0 + array)
            return template

        if isinstance(array, (list,tuple, GeneratorType)):
            print('Condition 2')
            for item in array:
                yield dtype(Coating(item.shape) * 0 + item)

class Coating(np.ndarray):

    def __init__(self, *args, **kwargs):
        if len(self.shape) < 2:
            raise Exception("Not accustomed for 1D")
    def ...
    ...

所以当我尝试触发两个条件(条件 1 或条件 2)时

iterable = Coat([np.zeros(shape = [20,35]),np.zeros(shape = [20,35]),np.zeros(shape = [20,35])])
print(iterable)
array = Coat(np.zeros(shape=[10,10]),dtype=np.uint8)
print(array)

它returns 我是发电机:

<generator object Coat.__new__ at 0x7fc2b4410bf8>
<generator object Coat.__new__ at 0x7fc291b5ef10>

new.

中没有打印任何内容

但是,如果我删除生成器创建,一切正常

class Coat:
    def __new__(cls, array, dtype=np.float32):

        if isinstance(array, np.ndarray):
            print('Condition 1')
            template = dtype(Coating(array.shape) * 0 + array)
            return template
        if isinstance(array, (list,tuple, GeneratorType)):
            print('Condition 2')

然后

Condition 2
None
Condition 1
[[0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]]

yield里面的__new__怎么可能表现的这么霸道,也就是说,弄得一团糟甚至如果它处于未触发的条件内?

How is it possible that yield inside __new__ behaves so dominantly, that is to say, makes a mess even if it is inside a condition that is not triggered?

这是 Python 语言的内置功能。 yield 在函数中的存在(函数中的任何位置)自动使该函数成为生成器函数。

来自文档:

7.7. The yield statement

[...]

Yield expressions and statements are only used when defining a generator function, and are only used in the body of the generator function. Using yield in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.

[...]

请注意,return 在生成器函数中的行为也与在普通函数中的行为略有不同。


另外我认为可能有更好的方法来处理这种情况,例如使用一个简单的函数而不是“class with __new__”。但我对你的代码了解不够,无法提出更好或更合适的解决方案。

但是,如果您只想“让它工作”,您也可以 yield 在第一个分支中:

class Coat:
    def __new__(cls, array, dtype=np.float32):
        if isinstance(array, np.ndarray):
            yield dtype(Coating(array.shape) * 0 + array)

        if isinstance(array, (list,tuple, GeneratorType)):
            for item in array:
                yield dtype(Coating(item.shape) * 0 + item)

然后Coat.__new__总是returns作为发电机。