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)

当前功能:

到目前为止,我已经写了几个类,MatrixDim, 和VecMatrix并且Vec都是 的子类Dim。创建矩阵时,首先会从列表列表开始,然后他们会创建一个矩阵,如下所示:

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

这应该创建一个Matrix. createdMatrix应该包含多个Dim长度相同的 s。这些Dims 中的每一个都应该包含多个Dim长度相同的 s,等等。最后Dim一个包含数字的 s 应该只包含数字,并且应该是 aVec而不是 a Dim

问题:

所有这些都适用于列表。但是,如果我要使用迭代器对象(例如返回的对象iter()),则它不会像我想要的那样起作用。

例如:

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

我的想法:

我相当肯定这正在发生,因为在Dim.__new__我迭代输入迭代时,当相同的迭代被传递给Matrix.__init__它时,它已经被迭代,因此看起来是空的,导致我得到空矩阵。

我尝试使用 复制迭代器itertools.tee(),但这也不起作用,因为我实际上并没有调用Matrix.__init__它在返回时被隐式调用Matrix.__new__,因此我不能使用与传递给的参数不同的参数来调用它Matrix.__init__。我想做的所有事情都遇到了同样的问题。

我有什么方法可以保留现有功能并允许matrix.Matrix()使用迭代器对象进行调用?

4

2 回答 2

3

关键是Vec.__init__被调用两次;一次在您的__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 回答