Python 通过函数对象

Python Object via Function

我试图理解(并最终使用)使用来自 numpy 的记录数组的对象数组的实现,来自这里:Numpy object array 在审查代码时,我显然正在学习关于 python 和我似乎无法完全理解以下内容:

在 obarray.py 文件中,一个函数用于创建新对象,我对

感到困惑
  1. 为什么要用一个函数,
  2. 参数如何作用于函数,
  3. 使用此函数与直接使用参数创建 class 和(大概使用参数作为属性)和
  4. 有何不同
  5. 这是什么 main.Obarray 我只是调用函数时得到的?

对于 1 和 2,我有预感参数会以某种方式变成对象 "local scope" 并且可能类似于对象属性?

这是来自 link 的新对象的代码:

import numpy as np
def make_obarray(klass, dtype):
    class Obarray(np.ndarray):
        def __new__(cls, obj):
            print "CLS:", cls
            print "OBJ:", obj
            A = np.array(obj,dtype=np.object)
            N = np.empty(shape=A.shape, dtype=dtype)
            for idx in np.ndindex(A.shape):
                for name, type in dtype:
                    N[name][idx] = type(getattr(A[idx],name))
            return N.view(cls)
        def __getitem__(self, idx):
            V = np.ndarray.__getitem__(self,idx)
            if np.isscalar(V):
                kwargs = {}
                for i, (name, type) in enumerate(dtype):
                     kwargs[name] = V[i]
                return klass(**kwargs)
            else:
                return V
        def __setitem__(self, idx, value):
            if isinstance(value, klass):
                value = tuple(getattr(value, name) for name, type in dtype)
            # FIXME: treat lists of lists and whatnot as arrays
            return np.ndarray.__setitem__(self, idx, value)
    return Obarray

以下是我的测试方式:

class Foo:
            def __init__(self, a, b):
                self.a = a
                self.b = b
            def __str__(self):
                return "<Foo a=%s b=%s>" % (self.a, self.b)
dtype = [("a",np.int),
                 ("b",np.float)]
FooArray = make_obarray(Foo, dtype)

A = FooArray([Foo(0,0.1),Foo(1,1.2),Foo(2,2.1),Foo(3,3.3)])
  1. 当我调用 FooArray 时,我得到 __main__.Obarray - 这是什么?
  2. 我作为参数输入的 "klass" 和 "dtype" 发生了什么?
  3. 这与以下内容有何不同:

Blockquote

class Obarray(np.ndarray):
    def __new__(cls,input_array, klass, dtype):
       obj = np.assarray(input_array).view(cls) 
       obj.klass = klass
       obj.dtype = dtype
       A = np.array(obj,dtype=np.object)
       N = np.empty(shape=A.shape, dtype=dt ype)
       for idx in np.ndindex(A.shape):
            for name, type in dtype:
                N[name][idx] = type(getattr(A[idx],name))
       obj.N = N.view(np.ndarray) 
       return obj

make_obarray函数是一个生产classes的工厂。 class 的 it returns 的方法将是可以访问函数的局部变量(例如 klassdtype 参数)的闭包,即使它已完成 运行.

这里有一个更简单的闭包,可以帮助您理解它们的工作原理:

def make_adder(x):
    def adder(y):
        return x + y
    return adder

make_adder 是一个工厂函数。它 returns 一个 adder 函数,它是一个闭包。即使在 make_adder 返回后,adder 仍然可以看到定义它的 make_adder 调用的 x 参数。

这与您显示的 numpy 代码相似。 make_obarray函数returns一个class,而不是一个函数,但除此之外几乎是一样的。 class 的限定名称将是 Python 2 中的 some_module.Obarray(或 Python 3 中的 some_module.make_obarray.<locals>.Obarray),其中 some_module 是它在其中定义的模块(或 __main__ 如果您已将其模块作为脚本执行)。返回的 class 的方法将能够看到传递给 make_obarrayklassdtype 参数,就像 adder 函数可以看到 [=在我更简单的例子中,make_adder 的 18=] 参数。

至于为什么你找到的代码是这样写的,我也不好说。也许代码的作者认为能够使用 isinstance 来区分具有不同 klassdtype 值的 Obarray 实例会很有用:

FooArray = make_obarray(Foo, dtype)
BarArray = make_obarray(Bar, some_other_dtype)

f = FooArray([Foo(1,2)])

print(isinstance(f, FooArray)) # True
print(isinstance(f, BarArray)) # False

如果 klassdtype 只是单个 class 的参数,您无法通过这种方式区分数组实例(尽管您可能会进行比较实例属性的等效检查)。