其实,c_并不是一个函数,它只是CClass类的一个实例,而CClass是定义了切片方法__getitem__的类,所以c_就可以使用切片,仿佛就像一个函数一样。
源代码是这样的
#头部声明c_变量
__all__ = [ 'ravel_multi_index', 'unravel_index', 'mgrid', 'ogrid', 'r_', 'c_', 's_', 'index_exp', 'ix_', 'ndenumerate', 'ndindex', 'fill_diagonal', 'diag_indices', 'diag_indices_from' ]
#CClass继承AxisConcatenator
class CClass(AxisConcatenator): """ Translates slice objects to concatenation along the second axis.
This is short-hand for ``np.r_['-1,2,0', index expression]``, which is useful because of its common occurrence. In particular, arrays will be stacked along their last axis after being upgraded to at least 2-D with 1's post-pended to the shape (column vectors made out of 1-D arrays). See Also -------- column_stack : Stack 1-D arrays as columns into a 2-D array. r_ : For more detailed documentation.
Examples -------- >>> np.c_[np.array([1,2,3]), np.array([4,5,6])] array([[1, 4], [2, 5], [3, 6]]) >>> np.c_[np.array([[1,2,3]]), 0, 0, np.array([[4,5,6]])] array([[1, 2, 3, ..., 4, 5, 6]])
"""
def __init__(self): AxisConcatenator.__init__(self, -1, ndmin=2, trans1d=0)
#关键一句,可见c_并不是函数,而是对象 c_ = CClass()
#AxisConcatenator中定义了切片方法__getitem__
class AxisConcatenator(object): """ Translates slice objects to concatenation along an axis.
For detailed documentation on usage, see `r_`. """ # allow ma.mr_ to override this concatenate = staticmethod(_nx.concatenate) makemat = staticmethod(matrixlib.matrix)
def __init__(self, axis=0, matrix=False, ndmin=1, trans1d=-1): self.axis = axis self.matrix = matrix self.trans1d = trans1d self.ndmin = ndmin
def __getitem__(self, key): # handle matrix builder syntax if isinstance(key, str): frame = sys._getframe().f_back mymat = matrixlib.bmat(key, frame.f_globals, frame.f_locals) return mymat
if not isinstance(key, tuple): key = (key,)
# copy attributes, since they can be overridden in the first argument trans1d = self.trans1d ndmin = self.ndmin matrix = self.matrix axis = self.axis
objs = [] scalars = [] arraytypes = [] scalartypes = []
for k, item in enumerate(key): scalar = False if isinstance(item, slice): step = item.step start = item.start stop = item.stop if start is None: start = 0 if step is None: step = 1 if isinstance(step, complex): size = int(abs(step)) newobj = linspace(start, stop, num=size) else: newobj = _nx.arange(start, stop, step) if ndmin > 1: newobj = array(newobj, copy=False, ndmin=ndmin) if trans1d != -1: newobj = newobj.swapaxes(-1, trans1d) elif isinstance(item, str): if k != 0: raise ValueError("special directives must be the " "first entry.") if item in ('r', 'c'): matrix = True col = (item == 'c') continue if ',' in item: vec = item.split(',') try: axis, ndmin = [int(x) for x in vec[:2]] if len(vec) == 3: trans1d = int(vec[2]) continue except Exception: raise ValueError("unknown special directive") try: axis = int(item) continue except (ValueError, TypeError): raise ValueError("unknown special directive") elif type(item) in ScalarType: newobj = array(item, ndmin=ndmin) scalars.append(len(objs)) scalar = True scalartypes.append(newobj.dtype) else: item_ndim = ndim(item) newobj = array(item, copy=False, subok=True, ndmin=ndmin) if trans1d != -1 and item_ndim < ndmin: k2 = ndmin - item_ndim k1 = trans1d if k1 < 0: k1 += k2 + 1 defaxes = list(range(ndmin)) axes = defaxes[:k1] + defaxes[k2:] + defaxes[k1:k2] newobj = newobj.transpose(axes) objs.append(newobj) if not scalar and isinstance(newobj, _nx.ndarray): arraytypes.append(newobj.dtype)
# Ensure that scalars won't up-cast unless warranted final_dtype = find_common_type(arraytypes, scalartypes) if final_dtype is not None: for k in scalars: objs[k] = objs[k].astype(final_dtype)
res = self.concatenate(tuple(objs), axis=axis)
if matrix: oldndim = res.ndim res = self.makemat(res) if oldndim == 1 and col: res = res.T return res
python看起来简单,其实一点都不简单啊!numpy真是个伟大的东东。