reps不可以为的参数类型 其实使用tuple函数转换成元组失败是因为tuple函数他需要的参数是一个可迭代的类型,如果不是的话就会抛出Typeerror的异常,抛出异常在源码中就会把值直接放入元组的第一个位置,这里的(reps,)也是一个元组类型。其实抛出异常对应的无非就是标量值,像int,True以及不能作为参数的float。
3.获取元组的长度
#这个其实很好理解
#要注意len((reps,))就是reps的元素个数
d = len ( tup )
print ( len (( True ,))) #1
对应上面的分析,这里无非也就是两种情况:
像int,True这样的标量值,他们被转换成的元素是(value,),这种形式的,所以获取长度肯定得到的是1;
剩下的一些序列化的参数,他们的len长度>=1,不确定,这就需要看这些参数中有多少个元素。
4.判断语句
if all ( x == 1 for x in tup ) and isinstance ( A , _nx . ndarray ):
# Fixes the problem that the function does not make a copy if A is a
# numpy array and the repetitions are 1 in all dimensions
return _nx . array ( A , copy = True , subok = True , ndmin = d )
else :
# Note that no copy of zero-sized arrays is made. However since they
# have no data there is no risk of an inadvertent overwrite.
c = _nx . array ( A , copy = False , subok = True , ndmin = d )
这里有几个函数需要注意:
all()函数。all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否有 0、、False 或者 iterable 为空。如果没有这些返回 True,否则返回 False。
_nx.array(A, copy=False, subok=True, ndmin=d)函数,简单来说就是创建一个ndarray数组。
copy参数:bool,可选。如果为True(默认值),那么对象被复制。否则,副本将仅当__array__返回副本。
subok参数:bool,可选。如果为True,则子类将被传递,通过,否则返回数组将被迫成为一个基类数组(默认)。
ndmin:int,可选。指定结果数组应有尺寸的最小数目。
isinstance(A, _nx.ndarray)函数。isinstance(object, classinfo)函数就是判断object对象类型是否是classinfo类型相同,相同则返回True,否则返回False。
#可以把这个先看成是import numpy as np
import numpy.core.numeric as _nx
print ( _nx . ndarray )
#从输出可以看出,isinstance(A, _nx.ndarray)判断A是不是ndarray类型的数据
<class numpy.ndarray>
这里的all(x == 1 for x in tup)就是为什么matrix不能使用的地方。
import numpy as np
reps = np . array ([[ 1 , 2 ],[ 3 , 4 ]])
print ( all (( x == 1 for x in reps )))
Traceback (most recent call last):
File "G:/Python源码/numpy_test/numpy_test.py", line 1763, in <module>
print(all((x == 1 for x in reps)))
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
然后我们来分析这个判断语句把那些情况筛选出去了:
all(x == 1 for x in tup) and isinstance(A, _nx.ndarray)。通过上面的分析,我们可以知道,如果传入的tup中的值都是1并且(and)我们的A是ndarray数组类型的话,直接return _nx.array(A, copy=True, subok=True, ndmin=d)。直接返回的是A这个ndarray数组,当然如果维度小于d的话,会自动增加d维度。
如果不是上面那种情况的话。执行c = _nx.array(A, copy=False, subok=True, ndmin=d)。ndmin参数说的就是c的ndim最少就是d,当然这里很自然的就会有三种情况:
c.ndim == d(也就是ndmin)
c.ndim > d[这个时候会继续执行5中的判断语句]
c.ndim < d(这种情况不可能发生,因为指定了ndmin = d)[所以不考虑]
5.判断语句
if (d < c.ndim):
tup = (1,)*(c.ndim-d) + tup
这是什么样的情况呢?因为c.ndim也就是c的维度比d也就是元组中的元素个数不匹配,或者说是要进行重复的A的维度和reps重复次数不匹配,这样可想而知是不可以的,所以加入了一个进行处理的代码。
import numpy as np
import numpy.core.numeric as _nx
A = np.array([[1,2],[3,4]])
tup = (2,)
d = len(tup)
c = _nx.array(A, copy=False, subok=True, ndmin=d)
if (d < c.ndim):
tup = (1,)*(c.ndim-d) + tup
print(d)#1
print(c.ndim)#2
print(tup)#(1, 2)
result
6.形成最终的shape_out
shape_out = tuple(s*t for s, t in zip(c.shape, tup))
因为我们在第五步的时候,已经将我们的c的ndim与我们的tup的维度匹配。我们把shape属性和我们需要进行重复次数的tup中对应的元素相乘形成新的数组,这个结果作为我们最终的shape。
7.tile函数的核心代码-对c的维度进行重复
n = c.size
if n > 0:
for dim_in, nrep in zip(c.shape, tup):
#nrep == 1就不需要进行复制了
if nrep != 1:
c = c.reshape(-1, n).repeat(nrep, 0)
n //= dim_in
第六步实现了对最终输出结果的shape的形成。之后就是很重要的如何去进行复制呢?这里的c.size得到的结果是c中元素的个数:
n = 0直接输出结果
n > 0执行复制元素的代码。
for dim_in , nrep in zip ( c . shape , tup ):
#nrep == 1就不需要进行复制了
if nrep != 1 :
c = c . reshape ( - 1 , n ) . repeat ( nrep , 0 )
n //= dim_in
从上面的分析我们也可以知道,到这一步,我们的shape和tup中的元素个数是相互匹配的。
如果tup中的值为1,则直接跳出,也就是不进行任何的复制操作。
如果tup中的值不为1,则执行c = c.reshape(-1, n).repeat(nrep, 0);n //= dim_in这两句代码。
这里的 c.reshape(-1,n)直接把c中的全部元素变成是一个一行n列的一个数组。
repeat(nrep, 0)函数会把c.reshape(-1,n)形成的哪个一行n列的数组复制nrep次,形成一个nrep行n列的数组。并且这里的0是参数axis的值,也就是行的方向进行重复。
n //= dim_in执行。" / "就一定表示 浮点数除法,返回浮点结果;" // "表示整数除法。
8.返回结果
return c . reshape ( shape_out )
3.示例代码
分析完了代码,看看怎么去使用。
1.A = array([1,2]);reps = (1,1)。1或者True(看成是1)...也是同样的步骤
从源码的分析上看:
首先一个函数体头部
对reps进行处理
tup = (1,1)
获取元组的长度d = 2
判断语句
if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray)
return _nx.array(A, copy=True, subok=True, ndmin=d)。这里因为A的ndim为1,d = 2,所以会把A扩展成ndim为2的数组。
import numpy as np
A = np.array([1,2])
reps = (1,1)
print(np.tile(A,reps))
[[1 2]]
2.A = array([[1,2],[3,4]]);reps = (1,2)。
从源码的分析上看:
首先一个函数体头部
对reps进行处理
tup = (1,2)
获取元组的长度d == 2
判断语句
if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray),因为tup中含有非1的元素,所以all中返回False,执行else语句。
c = _nx.array(A, copy=False, subok=True, ndmin=d),此时的c和A的shape相同。
判断语句
if (d < c.ndim),因为d == c.ndim所以不执行。
形成最终的shape_out
shape_out = tuple(s*t for s, t in zip(c.shape, tup)),这里会返回shape_out是(2,4)的shape。
tile函数的核心代码-对c的维度进行重复
n = c.size = 4
for dim_in, nrep in zip(c.shape, tup)。因为c.shape是(2,2),tup是(1,2),
执行第一次的时候,n //= dim_in,4 //= 2 ==2。
所以当执行第二次循环的时候,nrep == 2!1,所以执行 c = c.reshape(-1, n).repeat(nrep, 0)
c.reshap(-1,2)的结果是[[1 2][3 4]]。
[[1 2][3 4]].repeat(2,0)的执行结果是[[1 2] [1 2] [3 4] [3 4]]
返回结果
return c.reshape(shape_out),也就是array([[1,2,3,4],[1,2,3,4]]).reshape((2,4)),执行的结果是[[1 2 1 2] [3 4 3 4]]
import numpy as np
A = np.array([[1,2],[3,4]])
reps = (1,2)
print(np.tile(A,reps))
[[1 2 1 2]
[3 4 3 4]]
推荐阅读: