【问题标题】:Python Object via Function通过函数的 Python 对象
【发布时间】:2016-05-24 04:34:09
【问题描述】:

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

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

  1. 为什么要使用函数,
  2. 参数如何在函数中发挥作用,
  3. 使用此函数与直接使用参数创建类有何不同(可能使用参数作为属性),以及
  4. 这是什么ma​​in.Obarray 我刚刚调用该函数时得到的?

对于 1 和 2,我有一种预感,即参数会以某种方式成为对象的“本地范围”,并且可能类似于对象属性?

这是链接中新对象的代码:

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. 这与以下内容有何不同:

块引用

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

【问题讨论】:

  • 我不确定您的困惑是特定于这个numpy 代码还是更一般的。你了解闭包的工作原理吗?你以前用过collections.namedtuple 这样的类型工厂吗?
  • 这是此代码中出现的一个更普遍的问题,因此我将其用作示例。是的,我熟悉 namedtuple,但是 namedtuple 是不可变的

标签: python arrays inheritance numpy metaprogramming


【解决方案1】:

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

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

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

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

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

至于为什么你发现的代码是这样写的,我不能说。也许代码的作者认为能够使用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 只是单个类的参数,那么您无法以这种方式区分数组实例(尽管您可能会想出一个等效的检查来比较实例'属性)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多