4

Python(2.7)マトリックスモジュールを作成しようとしています。(私はnumpyについて知っています、これはただの楽しみのためです。)

私のコード:

from numbers import Number
import itertools

test2DMat = [[1,2,3],[4,5,6],[7,8,9]]
test3DMat = [[[1,2,3],[4,5,6],[7,8,9]],[[2,3,4],[5,6,7],[8,9,0]],[[9,8,7],[6,5,4],[3,2,1]]]

class Dim(list):
    def __new__(cls,inDim):
        # If every item in inDim is a number create a Vec
        if all(isinstance(item,Number) for item in inDim):
            #return Vec(inDim)
            return Vec.__new__(cls,inDim)

        # Otherwise create a Dim
        return list.__new__(cls,inDim)

    def __init__(self,inDim):
        # Make sure every item in inDim is iterable
        try:
            for item in inDim: iter(item)
        except TypeError:
            raise TypeError('All items in a Dim must be iterable')

        # Make sure every item in inDim has the same length
        # or that there are zero items in the list
        if len(set(len(item) for item in inDim)) > 1:
            raise ValueError('All lists in a Dim must be the same length')

        inDim = map(Dim,inDim)
        list.__init__(self,inDim)


class Vec(Dim):
    def __new__(cls,inDim):
        if cls.__name__ not in [Vec.__name__,Dim.__name__]:
            newMat = list.__new__(Vec,inDim)
            newMat.__init__(inDim)
            return newMat
        return list.__new__(Vec,inDim)

    def __init__(self,inDim):
        list.__init__(self,inDim)


class Matrix(Dim):
    def __new__(cls,inMat):
        return Dim.__new__(cls,inMat)

    def __init__(self,inMat):
        super(Matrix,self).__init__(inMat)

現在の機能:

これまでに、、、、およびのいくつかのクラスを作成しMatrixましDimVecMatrixVecは両方とものサブクラスですDim。マトリックスを作成するときは、最初にリストのリストから始めて、次のようなマトリックスを作成します。

>>> startingList = [[1,2,3],[4,5,6],[7,8,9]]
>>> matrix.Matrix(startingList)
[[1,2,3],[4,5,6],[7,8,9]]

これにより、が作成されますMatrix。作成されたものには、すべて同じ長さのMatrix複数のが含まれている必要があります。Dimこれらの各には、すべて同じ長さのDim複数のが含まれている必要があります。最後の、数字を含むものは、数字のみを含み、の代わりになります。DimDimVecDim

問題:

リストの場合、これはすべて機能します。ただし、代わりにイテレータオブジェクト(によって返されるオブジェクトなど)を使用した場合、iter()これは希望どおりに機能しません。

例えば:

>>> startingList = [[1,2,3],[4,5,6],[7,8,9]]
>>> matrix.Matrix(iter(startingList))    
[]

私の考え:

これが起こっていることはかなり確信しています。なぜならDim.__new__、入力iterableを反復処理すると、同じiterableが渡されたときに、Matrix.__init__すでに反復処理されているため、空のように見えて、空の行列が得られるからです。

を使用してイテレータをコピーしようとしましたitertools.tee()が、実際には呼び出さないため、リターンMatrix.__init__時に暗黙的に呼び出されMatrix.__new__、に渡されたパラメータとは異なるパラメータで呼び出すことができないため、これも機能しませんMatrix.__init__。私がやろうと思ったことはすべて、これと同じ問題に直面します。

既存の機能を保持matrix.Matrix()し、イテレータオブジェクトで呼び出すことを許可する方法はありますか?

4

2 に答える 2

3

重要なのは、2回Vec.__init__呼び出されることです。メソッド内に1回、メソッドから返すときに1回。したがって、すでに初期化されているものとしてマークし、すでに初期化されている場合から早期に戻る場合は、2番目の呼び出しを無視できます。__new____new__Vec.__init__

class A(object):
    def __new__(cls, param):
        return B.__new__(cls, param + 100)
class B(A):
    def __new__(cls, param):
        b = object.__new__(B)
        b.__init__(param)
        return b
    def __init__(self, param):
        if hasattr(self, 'param'):
            print "skipping __init__", self
            return
        self.param = param
print A(5).param
于 2012-10-18T15:40:05.150 に答える
0

渡される変数がタプルまたはリストであるかどうかを確認する必要があります。その場合は直接使用できます。そうでない場合は、イテレータをリスト/タプルに変換する必要があります。

if isinstance(inDim, collections.Sequence):
    pass
elif hastattr(inDim, '__iter__'): # this is better than using iter()
    inDim = tuple(inDim)
else:
    # item is not iterable

すべてのリストの長さが同じであることを確認するためのより良い方法もあります。

if len(inDim) > 0:
    len_iter = (len(item) for item in inDim)
    first_len = len_iter.next()
    for other_len in len_iter:
        if other_len != first_len:
            raise ValueError('All lists in a Dim must be the same length')
于 2012-10-18T15:39:06.353 に答える