Python Object via Function

时间:2016-02-12 21:34:43

标签: python arrays inheritance numpy metaprogramming

I am trying to understand (and eventually use) the implementation of object arrays using record arrays from numpy from here: Numpy object array in reviewing the code I am apparently learning new things about python and I can't seem to fully understand the following:

In the obarray.py file a function is used to create a new object and I am confused as to

  1. Why a function is used,
  2. How the arguments play into the function,
  3. How using this function differs from creating the class with the arguments directly and (presumably using the arguments as attributes), and
  4. What is this main.Obarray I get when I just call the function?

For 1 and 2 I have a hunch that the arguments somehow become that objects "local scope" and are perhaps similar to a object attribute?

Here is the code for the new object from the link:

eintraege.append( deutsch + '-' + englisch )

Here is how I am testing it:

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
  1. When I call FooArray I get 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)]) - what is this?
  2. What happened to "klass" and "dtype" that I entered as arguments?
  3. How is this different from something along the lines of:

Blockquote

__main__.Obarray

1 个答案:

答案 0 :(得分:1)

make_obarray函数是一个生成类的工厂。它返回的类的方法将是可以访问函数的局部变量(例如klassdtype参数)的闭包,即使它已经完成运行。

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

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

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

这与您展示的make_obarray代码相似。 some_module.Obarray函数返回一个类,而不是一个函数,但除此之外它几乎相同。该类的限定名称将在Python 2中为some_module.make_obarray.<locals>.Obarray(或在Python 3中为some_module),其中__main__是在其中定义的模块的名称(或{{ 1}}如果您已将其模块作为脚本执行)。返回类的方法将能够看到传递到klass的{​​{1}}和dtype参数,就像make_obarray函数可以看到adder参数一样在我更简单的例子中x

至于为什么你发现的代码是这样编写的,我无法说出来。也许代码的作者认为能够使用make_adder区分isinstance具有不同Obarrayklass值的实例是有用的:

dtype

如果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 klass只是单个类的参数,那么你就不能以这种方式区分数组实例(尽管你可能想出一个等价物检查是否比较了实例&#39;属性。)