2016-02-12 5 views
0

Я пытаюсь понять (и в конечном итоге использовать) реализацию массивов объектов с использованием массивов записей из numpy отсюда: Numpy object array в обзоре кода. Я, по-видимому, изучаю новые вещи о питоне, и я не могу показаться полностью понять следующее:Python Object через функцию

в obarray.py файле функция используется для создания нового объекта, и я запутался,

  1. Почему функция используется,
  2. Как аргументы играют в функция,
  3. Как использование этой функции отличается от создания класса с аргументами напрямую и (предположительно с использованием аргументов в качестве атрибутов) и
  4. Что это такое main .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. Как это отличается от чего-то вдоль линий:

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 
+0

Я не уверен, что ваше замешательство специфично для этого кода «numpy» или более общего. Вы понимаете, как работают замыкания? Вы когда-нибудь использовали типовую фабрику, например 'collections.namedtuple'? – Blckknght

+0

Это более общий вопрос, который возник в этом коде, поэтому я использую его в качестве примера. Да, я знаком с namedtuple, однако namedtuple неизменяемы – Skorpeo

ответ

0

make_obarray функция является фабрика, которая производит классы. Методами возвращаемого класса будут замыкания, которые могут получить доступ к локальным переменным функции (например, аргументы klass и dtype) даже после того, как они закончатся.

Вот гораздо проще замыкание, что может помочь вам понять, как они работают:

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__, если вы выполнили его модуль как скрипт).Методы возвращаемого класса смогут увидеть аргументы klass и dtype, переданные в make_obarray, так же как функция adder может видеть аргумент x в make_adder в моем более простом примере.

Что касается , почему код, который вы нашли, написан таким образом, я не мог сказать. Возможно, автор Кодекса думал, что это было бы полезно, чтобы иметь возможность использовать isinstance различать случаи Obarray с различными klass или 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 и dtype были только аргументы одного класса, то не мог Не скажите разницу между экземплярами массива таким образом (хотя вы, вероятно, могли бы получить эквивалентную проверку, сравнивающую атрибуты экземпляров).