2016-12-15 7 views
0

nオブジェクトの反復可能なプロパティをスキャンしようとしています。 pythonicループをレベルアップしてメソッド呼び出しに関数を渡すことで、任意の深さのネストループで関数を実行する方法を探しています。私は深さが3のときに最も内側のループを実行する以上のことはできませんでした。ここでは、ループ内の各ポイントで異なる値を照会している非動作のPython擬似コードがあります。他の難しさ、私は出力をキャプチャしてメソッドオブジェクトを渡して任意の深さにループをネストする

次の外側のループに
class Parent(object): 
    def __init__(self): 
     self.iterable = [None] * 2 
     self.result = self.iterable[:] 
    def loop(self, query_func): 
     def innerloop(): 
      for i, x in enumerate(self.iterable): 
       self.result[i] = query_func(x) 
      return self.result[:] 
     return innerloop 
class ChildA(Parent): 
    def __init___(self, A, object_to_queryA): 
     self.iterableA = [valueA for valueA in range(A)] 
     self.resultA = self.iterableA[:] 
     self.object_to_query = object_to_queryA 
    def query_valueA(self, x): 
     return self.object_to_query.some_query_function(x) 
class ChildB(Parent): 
    def __init___(self, B, object_to_queryB): 
     self.iterableB = [valueB for valueB in range(B))] 
     self.resultB = self.iterableB[:] 
     self.object_to_query = object_to_queryB 
    def query_valueB(self, x): 
     return self.object_to_query.some_other_query_function(x) 
class ChildC(Parent): 
    def __init___(self, C, , object_to_queryC): 
     self.iterableC = [valueC for valueC in range(C))] 
     self.resultC = self.iterableC[:] 
     self.object_to_query = object_to_queryC 
    def query_valueC(self, x): 
     return self.object_to_query.yet_another_query_function(x) 

を渡ししようとしていますされて、私は次のようにこれらのループを呼び出すことができるようにしたい:

import numpy 
query_objA, query_objB, query_objC = (SomeObjA(), SomeObjB(), SomeObjC()) 
A, B, C = (len(query_objA.data), len(query_objB.data), len(query_objC.data)) 
instA = ChildA(A, query_objA) 
instB = ChildB(B, query_objB) 
instC = ChildC(C, query_objC) 
my_scanning_func = ChildA.loop(ChildB.loop(ChildC.loop)) 
my_queries = numpy.array(my_scanning_func()).reshape(A,B,C) 
# Equally valid call example below: 
my_scanning_func2 = ChildB.loop(ChildC.loop(ChildA.loop)) 
my_queries2 = numpy.array(my_scanning_func2()).reshape(B,C,A) 

究極の機能イム探し

for i, x in enumerate(query_objA.data): 
    response[i] = instA.some_query_function(x) 
    for j, y in enumerate(query_objB.data): 
     response[i][j] = instB.some_other_query_function(y) 
     for k, z in enumerate(query_objC.data): 
      response[i][j][k] = instC.yet_another_query_function(z) 

ボーナスポイント、これはむしろ別のループメトを規定よりも、継承された再帰関数を介して行うことができれば下記に類似するが、任意の深さと順序のためになるため私が上にしようとしたように、各子供のためのds。最後の注意:私はPython 2.7互換のコードを書こうとしています。前もって感謝します!

+1

私はちょうどコードを見てきましたが、それはデコレータの仕事かもしれないようです。彼らがあなたの問題を解決できるかどうかを判断するのに十分に精通していますか? –

+0

'Parent'の最もインデントされた行は' self.result [i] = query_func() 'または' self.result [i] = query_func(x) 'でしょうか? –

+0

配列の実際の値はどこから来ますか? –

答えて

1

あとでdiscussion with the OP私はこれらの配列の構造を一般化することができるという良いアイデアを持っています。まず、あなたのオブジェクトは、あらかじめ定義された状態を反復したり、有効である)ので、オブジェクトのiterfaceはこのような何かを抽象化することになります。このインタフェースで

class Apparatus_interface: 
    def __init__(self,*needed_stuff): 
     #I have no idea how you are actually interacting with the device 
     self._device = SET_UP_OBJECT(needed_stuff) 

     #when iterating over this object we need to know how many states there are 
     #so we can predefine the shape (dimensions) of our arrays 
     self.num_of_states = 5 

     #it would make sense for each object to define 
     #the type of value that .query() returns (following spec of numpy's dtype) 
     self.query_type = [('f1', float), ('f2', float)] 

    def __iter__(self): 
     """iterates over the physical positions/states of the apperatus 
     the state of the device is only active in between iterations 

     * calling list(device) doesn't give you any useful information, just a lot of mechanical work 
     """ 
     for position in range(self.num_of_states): 
         #^not sure what this should be either, you will have a better idea 
      self._device.move_to(position) #represents a physical change in the device 
      yield position #should it generate different information? 

    def query(self): 
     return self._device.query() 

あなたは、デバイスの数を介して)(ネストされたループを繰り返すことによって、それらの間の状態の各組み合わせであなたの配列を生成します別のデバイスの状態を照会し(その値を配列に記録する)


通常、itertools.productを使用してデバイスの状態の組み合わせを生成することができますが、最適化のためにitertools.productは、物理デバイスが反復で使用される前に影響を与える反復コードを実行するため、最適化のこの種は適用されません実装:実際には配列を生成するために今すぐ

#values is a list that contains the current elements generated 
#the loop: for values[depth] in iterables[depth] basically sets the depth-th element to each value in that level of iterable 
def _product(iterables, depth, values): 
    if len(iterables)-depth == 1: 
     for values[depth] in iterables[depth]: 
      yield tuple(values) 
    else: 
     for values[depth] in iterables[depth]: 
      #yield from _product(iterables, depth+1, values) 
      for tup in _product(iterables, depth+1, values): 
       yield tup 

def product(*iterables): 
    """ 
    version of itertools.product to activate side-effects of iteration 
    only works with iterables, not iterators. 
    """ 
    values = [None]*len(iterables) 
    return _product(iterables, 0, values) 

を - すべての状態の製品を反復処理し、各1で問い合わせを行う最初のプロセスは、注意してstates変数私はplacを想定しようとしているので、未使用ですnumpyの配列のementは値が、その後一緒に配列を配置する機能を

def traverse_states(variable_devices, queried_device): 
    """queries a device at every combination of variable devices states""" 
    for states in product(*variable_devices): 
     yield queried_device.query() 

を生産した状態ではない反復取得順序によって決定されますが、かなり海峡前進です:

def array_from_apparatus(variable_devices, queried_object, dtype=None): 

    # the # of states in each device <==> # of elements in each dimension 
    arr_shape = [device.num_of_states for device in variable_devices] 

    iterator = traverse_states(variable_devices, queried_object) 
    if dtype is None: 
     dtype = queried_object.query_type 

    array = numpy.fromiter(iterator, dtype=dtype) 
    array.shape = arr_shape #this will fail if .num_of_states doesn't match the actual number of iterations 
    return array 

私はないんだけど私はこれについてまともなテストを行うことができたかどうかは確かですが、それはうまくいくと思います。

+1

あなたは 'yield queried_device.query()'を意味すると思います。 – aeolus

+0

'yield from _product(iterables、depth + 1、values)'は2.7では無効です。 'yield_product(iterables、depth + 1、values)は有効ですか? – aeolus

+1

私は_product(iterables、depth + 1、values)のiのために:yield i'](http://stackoverflow.com/questions/17581332/converting-yield-from-statement-to-python- 2-7-コード) –

1

あなたはarray[tup] = func(tup)tupはあなたがnumpy.fromiterとの組み合わせでitertools.productを使用することができ整数インデックスのタプルであるように、numpyの配列を生成したい場合は、私はこれがあなたの質問に答えるかはわからないが、私はそれが、少なくとも関連性があると思いますこのように:

import itertools 
#from itertools import imap as map #for python 2 
import numpy 

def array_from_func(dimensions, func, dtype=float): 
    ranges = (range(i) for i in dimensions) #ranges of indices for all dimensions 
    all_indices = itertools.product(*ranges) #will iterate over all locations regardless of # of dimensions 
    value_gen = map(func, all_indices) #produces each value for each location 
    array = numpy.fromiter(value_gen, dtype=dtype) 
    array.shape = dimensions #modify the shape in place, .reshape would work but makes a copy. 
    return array 

これは、インデックスは基本的な機能(私は最近考え出し秒1)を表示するために3つのデモを、ここで、実際のアレー出力に関連しているかを確認するために私には便利です

from operator import itemgetter 
>>> array_from_func((2,3,4), itemgetter(1),int) #second index 
array([[[0, 0, 0, 0], 
     [1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[0, 0, 0, 0], 
     [1, 1, 1, 1], 
     [2, 2, 2, 2]]]) 

>>> def str_join(it): 
     return ",".join(map(str,it)) 
#the '<U5' in next line specifies strings of length 5, this only works when the string will actually be length 5 
#changing to '<U%d'%len(str_join(dims)) would be more generalized but harder to understand 
>>> print(array_from_func((3,2,7), str_join, '<U5')) 
[[['0,0,0' '0,0,1' '0,0,2' '0,0,3' '0,0,4' '0,0,5' '0,0,6'] 
    ['0,1,0' '0,1,1' '0,1,2' '0,1,3' '0,1,4' '0,1,5' '0,1,6']] 

[['1,0,0' '1,0,1' '1,0,2' '1,0,3' '1,0,4' '1,0,5' '1,0,6'] 
    ['1,1,0' '1,1,1' '1,1,2' '1,1,3' '1,1,4' '1,1,5' '1,1,6']] 

[['2,0,0' '2,0,1' '2,0,2' '2,0,3' '2,0,4' '2,0,5' '2,0,6'] 
    ['2,1,0' '2,1,1' '2,1,2' '2,1,3' '2,1,4' '2,1,5' '2,1,6']]] 

>>> array_from_func((3,4), sum) #the sum of the indices, not as useful but another good demo 
array([[ 0., 1., 2., 3.], 
     [ 1., 2., 3., 4.], 
     [ 2., 3., 4., 5.]]) 

これはあなたが達成しようとしていることの線に沿っていると思いますが、私は確信していません...あなたが必要とするものをより具体的にすることができればフィードバックをお願いします。

関連する問題