我正在尝试编写一个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
,Dim
和Vec
。 Matrix
和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
。创建的Matrix
应包含多个Dim
的所有相同长度。这些Dim
中的每一个都应该包含多个Dim
的长度等等。最后Dim
,包含数字的那个,应该只包含数字,应该是{{ 1}}而不是Vec
。
所有这些都适用于列表。但是,如果我使用迭代器对象(例如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__
?
答案 0 :(得分: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
答案 1 :(得分:0)
您需要做的是检查传入的变量是元组还是列表。如果是,那么你可以直接使用它,否则你需要将迭代器转换为list / tuple。
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')