NDArray Routine

Array Manipulation

Shape Only

Routine Function Version Method Version
reshape(a,newshape[,order])
resize(a,new_shape) 大小可不同,重复a补不足 0补不足
ravel(a[,order]) 展平视图
.flatten([order]) 展平副本
shape(a)
size(a)

Order Alteration

Routine Function Version Method Version
transpose(a[,axes]) 调整轴顺序,缺省逆序即转置
moveaxis(a,source,destination) 移动数组轴到新位置
rollaxis(a,axis[,start]) 将指定后向插入至指定位置(缺省0)
swapaxes(a,axis1,axis2) 交换轴
flip(m[,axis]) 沿指定轴反向,缺省所有轴
fliplr(m) 左右反向(沿第2轴)
flipud(m) 上下反向(沿第1轴)
roll(a,shift[,axis]) 沿轴滚动shift
rot90(m[,k,axes]) axes指定的平面中旋转k次90度
lib.stride_tricks.as_strided(x[,shape,...]) 利用给定shape、stride在x上创建视图

维数改变

Routine Function Version Method Version
atleast_1d(*arys) prepend维度直至维度至少维数至少1
atleast_2d(*arys)
atleatt_3d(*arys)
broadcast(*arys) 广播、打包输入对应元素的元组迭代器,类似zip
broadcast_to(array,shape[,subok]) 广播为指定shape
boradcast_arrays(*args,**kwargs) 输入的广播结果列表
expand_dims(a,axis) 在指定位置插入新轴
squeeze(a[,axis]) 删除大小为1维度

插入、删除元素

Routine Function Version
delete(arr,obj[,axis]) 删除obj指定部分,缺省按展平数组删除
insert(arr,obj,values[,axis]) 缺省按展平数组插入
append(arr,values[,axis]) 缺省arrvalues展平再添加
trim_zeros(filt[,trim]) trim前导、尾随0,缺省两边

改变类型

Routine Function Version Method Version
asarray(a[,dtype,order]) 转换为数组
asarray_chkfinite(a[,dtype,order]) 检查NaNinf
asanyarray(a[,dtype,order]) 转换为数组,数组子类则不变
ascalar(a) 将大小为1的数组转换为等效标量
require(a[,dtype,requirements]) 创建满足要求ndarray.flags数组
asfortranarray(a[,dtype]) 转换为Fortran-contiguous风格内存布局
ascontiguousarray(a[,dtype]) 转换为C-contiguous风格内存布局
asmatrix(data[,dtype])
asfarray(a[,dtype]) 转换为浮点类型
.astype(dtype[,order,casting,...]) 转换为指定类型
  • numpy中数组不是仅有C、Fortran风格内存布局,对数组的形态 变换会导致内存布局不为任何风格内存布局

组合数组

Routine Function Version
concatenate((a1,a2,...)[,axis,out]) 沿现有轴连接数组
stack(arrays[,axis,out]) 创建给定(新)轴堆叠数组
row_stack(tup)/vstack(tup) 沿第1(竖直)轴堆叠
column_stack(tup)/hstack(tup) 沿第2(水平)轴堆叠
dstack(tup) 沿第3轴堆叠
block(arrays) 按照arrays中给定数组块、位置组装

拆分数组

Routine Function Version
split(ary,indices_or_sections[,axis]) 沿轴拆分成视图
array_split(ary,indices_or_sections[,axis]) split,但可处理不整除拆分
vsplit(ary,indices_or_sections) 沿第1(竖直)轴拆分
hsplit(ary,indices_or_sections) 沿第2(水平)轴拆分
dsplit(ary,indices_or_sections) 沿第3轴拆分

Padding

Function Desc
pad(array,pad_width[,mode])

Index Routine

  • 结果数组shape考虑逻辑链

    • 确定输出数组的维数ndim
    • 确定参数数组原维度轴位置、补1轴位置,参数维度轴对齐
    • 修正各维度大小
      • 沿轴操作:保持不变
      • 沿轴采样:采样数目
      • 沿轴concate:维度相加
      • 沿轴聚集:删除维度
      • 沿轴切片聚集:删除其余维度
  • numpy中(多维)索引往往使用整数高级索引的方式返回

    • np.ndarray数组:首维度各分量分别表示各维度的高级 索引
    • list、tuple:各元素分别为各维度的高级索引

数组无关切片、高级索引

Routine Function Version 返回值类型
s_[] 支持多维切片生成,类slice() 切片、元组
index_exp[] s_,但总返回元组 元组
r_[] 沿第1轴concate切片、数组、标量 数组
c_[] 沿第-1轴concate切片、数组、标量(1维则被视为列向量) 数组
ravel_multi_index(multi_index,dims[,mode,order]) 计算高级索引multi_indexdims数组展平后的位置 数组
unravel_index(indices,shape[,order]) ravel_multi_index逆向 元组
  • np.r_[]np.c_[]除可concate切片方便生成数组,还可以 传递两个参数修改行为

    • r/c字符被设置时,返回矩阵

      • 1维数组,r被设置时返回1 N矩阵,c被设置时 返回N 1矩阵
      • 2维数组,rc被设置时,结果矩阵相同
    • <axis>[,<ndim>,<ori_pos>]三个整形,决定shape

      |参数|说明|np.r_[]缺省值|np.c_[]缺省值| |——-|——-|——-|——-| |<axis>|concate执行轴|0|-1| |<ndim>|目标维数,仅在其大于结果维数时才生效|1|2| |<ori_pos>|原数据轴所在的位置|-1,即prepend全1轴|0,即postpend全1轴|

    • 相同参数时,两者结果相同,可根据不同数组设置合适的 参数相互实现

      • np.r_[]可视为参数缺省为0,1,-1
      • np.c_[]可视为参数缺省为-1,2,0
  • np.r_np.c_分别是np.lib.index_tricks.RClassnp.lib.index_tricks.CClass实例
  • np.s_np.index_exp均是 np.lib.index_tricks.IndexExpression实例,仅初始化参数 不同

网格

Routine Function Version 返回值类型
ix_(*args) args为基点创建开网格(仅设置基点、维度) 元组
meshgrid(*xi,**kwargs) xi作为基点创建稠密网格(所有网格点高级索引) 列表
mgrid[] 根据切片创建稠密网格 数组
ogrid[] 根据切片创建开网格 列表
indices(dimensions[,dtype,sparse]) dimensions作为各维度长创建网格 数组、元组
  • 开网格广播即可得到稠密网格

值相关索引

Routine Function Version Method Version
nonzero(a) 非0元素整形高级索引
where(condition,[x,y]) condition对应整形高级索引,给出x,y时则从中抽取元素
flatnonzero(a) 展平非0位置

特殊位置索引

Routine Function Version
diag_indices(n[,ndim]) ndim维长为n数组对角索引
diag_indices_from(arr) 获取arr对角索引
mask_indices(n,mask_func[,k]) 根据mask_func获取n * n数组索引
tril_indices(n[,k,m]) n * m的下三角索引
triu_indices(n[,k,m]) n * m的上三角索引
tril_indices_from(arr[,k]) arr的下三角索引
triu_indices_from(arr[,k]) arr的下三角索引
  • np.ndindex(*args) == np.broadcast(*np.indices(*args))

Searching 索引

Routine Function Version Method Version
argwhere(a) 非0点坐标数组
argmax(a[,axis,out]) 展平后位置,存在NaN则返回0
argmin(a[,axis])
nanargmax(a[,axis]) 忽略NaN
nanargmin(a[,axis])
searchsorted(a,v[,side,sorter]) 应插入(保持有序)位置

Value Manipulation

Value Extraction

Routine Function Version Method Version
take(a,indices[,axis,out,mode]) indices沿给定轴获取超平面(缺省将数组展平)
take_along_axis(arr,indices,axis) arrindices沿axis匹配,选取元素
compress(condition,a[,axis,out]) 按bool数组condition沿给定轴axis选取超平面(缺省将数组展平)
extract(condition,arr) 在展平数组上抽取元素
choose(a,choices[,out,mode]) 根据a广播后元素值选择choices中数组填充对应位置
select(condlist,choicelist[,default]) condlist中首个真值对应的choicelist数组填充对应位置
diag(v[,k]) 从2维v抽取对角、或以1维v作为对角
diagonal(a[,offset,axis1,axis2]) 返回给定对象
  • take:沿给定轴从数组中获取元素

    • axisNone时,按展平后获取indices指定元素, 非None
      • 函数行为同高级索引
      • 指定axis可以简化通过高级索引获取指定轴的元素
    • 基本元素为数组在该轴的切片
    1
    2
    3
    4
    5
    6
    Ni, Nk = a.shape[:axis], a.shape[axis+1:]
    Nj = indices.shape
    for ii in np.ndindex(Ni):
    for jj in np.ndindex(Nj):
    for kk in np.ndindex(Nk):
    out[ii+jj+kk] = a[ii+(indices[jj],)+kk]
  • take_along_axis:匹配给定轴方向的1维索引、数据切片, 获取元素

    • 基本元素为单个元素
      • indicesarr对齐,除给定维度外,其余维度 大小均须相同
      • 其余维度给定下,按照indices在超平面上给出的 位置获取对应的元素
      • take以超平面为单位获取整个超平面的元素,而 take_along_axis按元素为单位,沿给定轴方向调整 元素顺序
    • np.argsortnp.argpartition等函数能够返回适合此 函数的索引
    1
    2
    3
    4
    5
    6
    7
    8
    9
    N1, M, Nk = arr.shape[:axis], arr.shape[axis], arr.shape[axis+1:]
    J = indices.shape[axis]
    out = np.empty(Ni + (J,) + Nk)
    for ii in np.ndindex(Ni):
    for kk in np.ndindex(Nk):
    a_1d = arr[ii + np.s_[:,] + kk]
    indices_1d = indices[ii + np.s_[:,] +kk]
    out_1d = out[ii + np.s_[:,] + kk]
    out_1d = a_1d[indices_1d[j]]
  • np.choose

    • choices:数组序列,其中数组和a需广播兼容
      • 若本身为数组,则其最外层被视为序列
    • 逻辑
      • achoices中数组共同广播
      • 广播结果的shape即为结果shape,其中a取值为n 处用数组choices[n]填充
    1
    np.choose(a,choices) == np.array([choices[a[I]][I] for I in np.ndindex(a.shape)])
  • np.select

    • 使用各位置condlist首个真值出现的位序值构建a,则 等价于np.choose(a,choicelist) (不考虑缺省值)
  • np.extract

    • 等价于np.compress(np.ravel(condition), np.ravel(arr))
    • condition为bool数组,也等价于arr[condition]

Value Modification

Routine Function Version Method Version
place(arr,mask,vals) 按照mask循环使用vals中值替换arr中元素
put(a,ind,v[,mode]) place,但根据展平索引ind替换
put_along_axis(arr,indices,values,axis) 匹配indicesarr沿axis分量,替换值
copyto(dst,src[,casting,where]) 根据bool数组where替换dst中元素
putmask(a,mask,values) copyto
fill_diagonal(a,val[,wrap]) val填充a的主对角
clip(a,a_min,a_max[,out=None,**kwargs]) 裁剪值
  • wheremaskcondition缺省为、等价为bool数组
  • np.clipufunc

Sorting

Routine Function Version Method Version
sort(a[,axis,kind,order,]) 在位排序
lexsort(keys[,axis]) 根据keys中多组键沿axis轴排序(靠后优先级高)
msort(a) 沿第1轴排序
argsort(a[,axis,kind,order]) 沿axis方向间接排序
sort_complex(a) 先实、后虚排序
partition(a,kth[,axis,kind,order]) 以第kth大小数划分
argpartition(a,kth[,axis,kind,order]) 间接分段
  • lexsort:按照axis方向、以keys中数组顺序作为权重 进行间接排序
    • keys:数组序列或2维以上数组
      • 数组最高维视为序列
      • keys为数组时,最高维被省略
      • 多个数组视为权重不同的排序依据,靠后优先级高
    • axis:排序所沿轴方向,缺省为-1,沿最低维轴排序
      • 可视为按keys中数组逆序优先级,取用各数组沿轴 方向的间接排序结果
      • 即对每个第1轴、axis构成平面,优先考虑第1轴末尾 axis方向数组进行排序,再依次考虑前序
    • lexsortargsort排序方向相同时,lexsort结果中 最后子数组和argsort结果应差别不大 (排序方向相同而不是axis参数取值相同)

Logical Test

真值测试

Routine Function Version Method Version
all(a[,axis,out,keepdims]) 给定轴方向所有元素为真
any(a[,axis,out,keepdims]) 给定轴方向存在元素为真

数组内容

Routine Function Version
isfinite(x,/[,out,where,casting,order,...]) 逐元素是否有限
isinf(x,/[,out,where,casting,order,...])
isnan(x,/[,out,where,casting,order,...])
isnat(x,/[,out,where,casting,order,...]) 逐元素是否NaT
isneginf(x,/[,out])
isposinf(x,/[,out])
  • isneginfisposinf行为类似ufunc,但不是

类型测试

Routine Function Version
iscomplex(x)
iscomplexobj(x) 复数类型或复数值
isfortran(a) Fortran contiguous
isreal(x)
isrealobj(x) 实数类型或实数值
isscalar(x)

Mathmatics

  • 部分数学函数为ufunc

UFunc初等运算

Function Desc
add(x1,x2,/[out,where,casting,order,...])
subtract(x1,x2,/[,out,where,casting,...])
multiply(x1,x2,/[,out,where,casting,...])
divide(x1,x2,/[,out,where,casting,...])
true_devide(x1,x2,/[,out,where,casting,...])
floor_devide(x1,x2,/[,out,where,casting,...])
logaddexp(x1,x2,/[,out,where,casting,...]) ln(x1+x2)
logaddexp2(x1,x2,/[,out,where,casting,...]) log_2 (x1+x2)
negative(x,/[,out,where,casting,order,...])
positive(x,/[,out,where,casting,order,...])
power(x1,x2,/[,out,where,casting,order,...]) x1^x2
float_power(x1,x2,/[,out,where,casting,...]) x1^x2
remainder(x1,x2,/[,out,where,casting,...]) 求余/取模
mod(x1,x2,/[,out,where,casting,order,...]) 求余/取模
fmod(x1,x2,/[,out,where,casting,order,...]) 求余/取模
divmod(x1,x2,/[,out1,out2],/[out,...])
absolute(x,/[,out,where,casting,order,...])/abs
rint(x,/[,out,where,casting,order,...])
sign(x,/[,out,where,casting,order,...])
heaviside(x1,x2,/[,out,where,casting,...]) 阶跃函数
conj(x,/[,out,where,casting,...]) 对偶
exp(x,/[,out,where,casting,order,...])
exp2(x,/[,out,where,casting,order,...])
log(x,/[,out,where,casting,order,...])
log2(x,/[,out,where,casting,order,...])
log10(x,/[,out,where,casting,order,...])
expm1(x,/[,out,where,casting,order,...]) 计算exp(x)-1
log1p(x,/[,out,where,casting,order,...]) 计算ln(x+1)
sqrt(x,/[,out,where,casting,order,...]) 非负平方根
square(x,/[,out,where,casting,order,...])
cbrt(x,/[,out,where,casting,order,...]) 立方根
reciprocal(x,/[,out,where,casting,order,...]) 倒数
gcd(x,/[,out,where,casting,order,...]) 最大公约数
lcm(x,/[,out,where,casting,order,...]) 最小公倍数
  • out参数可用于节省内存,如:G=A*B+C
    • 等价于:t1=A*B; G=t1+C; del t1;
    • 可利用out节省中间过程内存:G=A*B; np.add(G,C,G)

UFunc Floating函数

Routine Function Version
fabs(x,/[,out,where,casting,order,...]) 不可用于复数
signbit(x,/[,out,where,casting,order,...]) signbit是否设置,即<0
copysign(x1,x2,/[,out,where,casting,order,...]) 根据x1设置x2signbit
nextafter(x1,x2,/[,out,where,casting,order,...]) x1朝向x2的下个浮点数,即变动最小精度
spacing(x,/[,out,where,casting,order,...]) x和最近浮点数距离,即取值的最小精度
modf(x[,out1,out2],/[,out,where],...) 返回取值的整数、小数部分
ldexp(x1,x2,/[,out,where,casting,...]) 计算x1*2**x2,即还原2为底的科学计数
frexp(x[,out1,out2],/[,out,where],...) 返回2为底的科学计数的假数、指数
floor(x,/,out,*,where,...)
ceil(x,/,out,*,where,...)
trunc(x,/,out,*,where,...)
rint(x,/[,out,where,casting,order,...]) 最近整数
around(a[,decimals,out])/round/round_
fix(x[,out]) 向零点取整
  • np.fix不是ufunc,但行为类似

比较函数

  • 数值比较

    • np.equal()更多应用于整形比较,比较浮点使用 np.isclose()更合适
    • np.allclose()则是判断数组整体是否相同
    • array_equal(a1,a2)数组a1a2相同
    • array_equiv(a1,a2)数组a1a2广播后相同
  • 逻辑运算符

    • &|~:逐元素逻辑运算
      • 优先级高于比较运算符
    • andornot:整个数组的逻辑运算
  • np.maximum()np.minimum()函数

    • max()寻找最大值效率比np.maximum.reduce()低,同样 min()效率也较低

UFunc比较函数

Routine Function Version Method Version
greater(x1,x2,/[,out,where,casting,...]) >
greater_equal(x1,x2,/[,out,where,casting,...]) >=
less(x1,x2,/[,out,where,casting,...]) <
less_equal(x1,x2,/[,out,where,casting,...]) <=
not_equal(x1,x2,/[,out,where,casting,...]) !=
equal(x1,x2,/[,out,where,casting,...]) ==
logical_and(x1,x2,/[,out,where,casting,...]) 逐元素and and
logical_or(x1,x2,/[,out,where,casting,...]) or
logical_xor(x1,x2,/[,out,where,casting,...])
logical_not(x1,x2,/[,out,where,casting,...]) not
maximum(x1,x2,/[,out,where,casting,...]) 逐元素选择较大者
minimum(x1,x2,/[,out,where,casting,...]) 逐元素选择较小者
fmax(x1,x2,/[,out,where,casting,...]) 逐元素选择较大者,忽略NaN
fmin(x1,x2,/[,out,where,casting,...]) 逐元素选择较小者,忽略NaN

非UFunc

Routine Function Version
isclose(a,b[,rtol,atol,equal_nan]) 逐元素容忍度范围内相等
allclose(a,b[,rtol,atol,equal_nan]) all(isclose())
array_equal(a1,a2[,equal_nan]) 数组整体
array_equiv(a1,a2) 广播后相等

UFunc Bit-twiddling函数

Routine Function Version
bitwise_and(x1,x2,/[,out,where,...])
bitwise_or(x1,x2,/[,out,where,...])
bitwise_xor(x1,x2,/[,out,where,...])
invert(x,/[,out,where,casting,...])
left_shift(x1,x2,/[,out,where,casting...])
left_shift(x1,x2,/[,out,where,casting...])

UFunc 三角函数

Routine Function Version
sin(x,/[,out,where,casting,order,...])
cos(x,/[,out,where,casting,order,...])
tan(x,/[,out,where,casting,order,...])
arcsin(x,/[,out,where,casting,order,...])
arccos(x,/[,out,where,casting,order,...])
arctan(x,/[,out,where,casting,order,...])
arctan2(x1,x2,/[,out,where,casting,order,...]) 考虑象限下,arctan(x1/x2)
hypot(x1,x2,/[,out,where,casting,order,...]) 计算斜边
sinh(x,/[,out,where,casting,order,...]) 双曲正弦
cosh(x,/[,out,where,casting,order,...])
tanh(x,/[,out,where,casting,order,...])
arcsinh(x,/[,out,where,casting,order,...])
arccosh(x,/[,out,where,casting,order,...])
arctanh(x,/[,out,where,casting,order,...])
deg2rad(x,/[,out,where,casting,order,...]) 角度转换为弧度
rad2deg/degrees(x,/[,out,where,casting,order,...]) 弧度转换为角度

基本数学

Routine Function Version Method Version
prod(a[,axis,dtype,out,keepdims,...])
nanprod(a[,axis,dtype,out,keepdims,...])
sum(a[,axis,dtype,out,keepdims,...])
nansum(a[,axis,dtype,out,keepdims,...])
cumprod(a[,axis,dtype,out,keepdims,...]) 累乘(也可用ufunc.accumulate
cumsum(a[,axis,dtype,out,keepdims,...]) 累加
nancumprod(a[,axis,dtype,out,keepdims,...]) NaN视为1
nancumsum(a[,axis,dtype,out,keepdims,...]) NaN视为0
diff(a[,n,axis,prepend,append,...]) 沿给定轴1阶差分(保持类型不变,注意溢出)
ediff1d(ary[,to_end,to_begin] 沿展平顺序1阶差分
gradient(f,*varargs,**kwargs) 梯度
cross(a,b[,axisa,axisb,axisc,axis]) 向量叉积
trapz(y[,x,dx,axis]) 梯形法则定积分

复数运算

Routine Function Version Method Version
angle(z[,deg]) 角度
real(val) 实部
imag(val) 虚部
conj/conjugate(x,/[,out,where,casting,order,...]) 复共轭

Miscellaneous

Routine Function Version
nan_to_num(x[,copy,nan,posinf,neginf]) 替换NaNinf为数值
real_if_close(a[,to]) 虚部接近0则省略
interp(x,xp,fp[,left,right,period]) 1维线性插值
polyfit(x,y,deg[,rcond,full,w,cov]) 最小二乘多项式拟合

Statistics

  • axis=None:默认值None,表示在整个数组上执行操作

Count

Routine Function Version
count_nonzero(a[,axis])

顺序

Routine Function Version Method Version
amin/min(a[,axis,out,keepdims,initial,where])
amax/max(a[,axis,out,keepdims,initial,where])
nanmin(a[,axis,out,keepdims,initial,where]) 忽略NaN
nanmax(a[,axis,out,keepdims,initial,where])
ptp(a[,axis,out,keepdims]) 极差
percentile(a,q[,axis,out,...]) q取值[0-100]
nanpercentile(a,q[,axis,out,...])
quantile(a,q[,axis,out,overwrite_input,...]) q取值[0,1]
nanquantile(a,q[,axis,out,...])

均值、方差

Routine Function Version Method Version
median(a[,axis,out,overwrite_input,keepdims])
average(a[,axis,weights,returned])
mean(a[,axis,dtype,out,keepdims])
std(a[,axis,dtype,out,ddof,keepdims]) 标准差
var(a[,axis,dtype,out,ddof,keepdims]) 方查
nanmedian(a[,axis,out,overwrite_input,...])
nanmean(a[,axis,dtype,out,keepdims])
nanstd(a[,axis,dtype,out,ddof,keepdims])
nanvar(a[,axis,dtype,out,ddof,keepdims])

相关系数

Routine Function Version
corrcoef(x[,y,rowvar,bias,ddof]) Pearson积差相关系数
correlate(a,v[,mode]) 卷积
convolve(a,v[,mode]) 离散、线性卷积
cov(m[,y,rowvar,bias,ddof,fweights,...]) 方差

Array Creation

Ones and Zeros

Routine Function Version
empty(shape[,dtype,order]) 无初始化
empty_like(prototype[,dtype,order,subok,...]) shape、类型同prototype
eye(N[,M,k,dtype,order]) 对角为1的2D数组
identity(n[,dtype]) 单位矩阵数组
ones(shape[,dtype,order])
ones_like(a[,dtype,order,subok,shape])
zeros(shape[,dtype,order])
zeros_like(a[,dtype,order,subok,shape])
full(shape,fill_value[,dtype,order]) full_value数组
full_like(a,fill_value[,dtype,order,...])

Numerical Ranges

Routine Function Version
arange([start,]stop[,step][,dtpye]) 给定间距
linspace(start,stop[,num,endpoint]) 给定数量,等差均分
geomspace(start,stop[,num,endpoint,base,...]) 等比均分
logspace(start,stop[,num,endpoint,base,...]) log10尺度上均分,同np.power(10, np.linspace(start,stop))

Repetition

Routine Function Version Method Version
tile(A,reps) 重复A(可是数组)创建一维数组
repeat(a,repeats[,axis]) 沿已有轴重复a创建

Matrix-Relative

Routine Function Version
diag(v[,k]) 从2维v抽取对角、或以1维v作为对角
diagflat(v[,k])
tri(N[,M,k,dtype]) 对角线及以下为1、其余为0矩阵
tril(m[,k]) 下三角
triu(m[,k]) 上三角
vander(x[,N,increasing]) Vandermonde矩阵

From Existing Data

Routine Function Version
array(object[,dtype,copy,order,subok,ndmin])
copy(a[,order])
frombuffer(buffer[,dtype,count,offset] 从缓冲(如字节串)创建数组
fromfunction(function,shape,**kwargs) 以坐标为参数,从函数创建数组
fromiter(iterable,dtype[,count])
  • 改变数组数据类型也可以视为是创建新数组

转入、转出

类型转出

Routine Method Version
.item(*args) 根据args选择元素复制至标准python标量
.tolist() 转换为.ndim层嵌套python标量列表
.itemset(*args) 插入元素(尝试转换类型)
.byteswap([inplace]) 反转字节序
.view([dtype,type]) 创建新视图
.getfield(dtype[,offset]) 设置数据类型为指定类型
.setflags([write,align,uic]) 设置标志
.fill(value) 使用标量填充

打包二进制

Function Desc
packbits(a[,axis,bitorder]) 元素打包为标志位,0补足,返回uint8数组
upackbits(a[,axis,bitorder])

输入、输出

Routine 格式 输入 输出
dump(file) pickle 文件
tofile(fid[,sep,format]) 内存内容(sep="")、分割符串 文件
fromfile(file[,dtype,count,sep,offset]) 字节串、分割符串 文件 数组
save(file,arr[,allow_pickle,fix_imports]) .npy 数组 文件
savez(file,*args,**kwds) 非压缩的.npz (多个)数组 文件
savez_compressed(file,*args,**kwds) 压缩的.npz (多个)数组
load(file[,mmap_mode,allow_pickle,...]) .npy.npz、pickle 文件 数组
savetxt(fname,X[,fmt,delimiter,newline,...]) 分割符串 二维以下数组 文件
loadtxt(fname[,dtype,comments,delimiter,...]) 分割符串 文件 数组
genfromtxt(fname[,dtype,comments,...]) 分割符串 文件 数组
fromregex(file,regexp,dtype[,encoding]) 正则表达式结构 文件 数组

Routine Function Version Method Version
array2string(a[,max_line_width,precision,...]) __str__
array_repr(arr[,max_line_width,precision,...]) __repr__
array_str(arr[,max_line_width,precision,...]) __str__
dumps() pickle序列化
loads(*args,**kwargs) pickle 字节串 数组
tobytes([order])/tostring 内存内容字节串
fromstring(string[,dtype,count,sep]) 从字符串、字节串(sep="",且缺省)创建1维数组
  • np.loadspickle.loads,不建议使用
  • np.fromstring
    • sep="":从二进制字节串中创建数组,类frombuffer
    • sep置为分割符时,只能指定一种元素分隔符,也只能 解析1维数组的字符串

字符串输出格式

Routine Function Version
format_float_positional(x[,precision,...]) 格式化位置计数
format_float_scientific(x[,precision,...]) 格式化科学计数
set_printoptions([precision,threshold,...])
get_printoptions()
set_string_function(f[,repr])
printoptions(*args,**kwargs) 设置打印选项的上下文管理器
binary_repr(num[,width]) 二进制字符串
base_repr(number[,base,padding])

Data Source

Function Desc
DataSource([destpath]) 通用数据源文件(file,http,ftp等)

Scala 基本实体

Expression

表达式:可计算的语句

  • value:常量,引用常量不会再次计算
    • 不能被重新赋值
    • 类型可以被推断、也可以显式声明类型
    • 可以被声明为lazy,只有被真正使用时才被赋值
1
2
3
val constant = 1
lazy val lazy_constant = 1
var variable = 1
  • variable:变量,除可重新赋值外类似常量

Unified Types

  • Scala中所有值都有类型,包括数值、函数

类型层次结构

scala_unified_types_diagram

  • Any:顶级类型,所有类型超类

    • 定义一些通用方法
      • equals
      • hashCode
      • toString
  • AnyVal:值类型

    • 有9个预定义非空值类型
      • Double
      • Float
      • Long
      • Int
      • Short
      • Byte
      • Char
      • Boolean
      • Unit:唯一单例值()
    • 值类型可以按以下方向转换(非父子类之间) scala_value_types_casting_diagram
  • AnyRef:引用类型

    • 所有非值类型都被定义为引用类型
    • 用户自定义类型都是其子类型
    • 若Scala被应用于Java运行环境中,AnyRef相当于 java.lang.object
  • Nothing:底部类型,所有类型的子类型

    • 没有值是Nothing类型
    • 可以视为
      • 不对值进行定义的表达式的类型
      • 不能正常返回的方法
    • 用途
      • 给出非正常终止的信号:抛出异常、程序退出、死循环
  • NULL:所有引用类型的子类型

    • 唯一单例值null
    • 用途
      • 使得Scala满足和其他JVM语言的互操作性,几乎不应该 在Scala代码中使用

基本数据类型

数据类型 取值范围 说明
Byte $[-2^7, 2^7-1]$
Short $[-2^{15}, 2^{15}-1]$
Int $[-2^{31}, 2^{31}-1]$
Long $[-2^{63}, 2^{63}]$
Char $[0, 2^{16}-1]$
String 连续字符串 按值比较
Float 32bits浮点
Double 64bits浮点
Boolean truefalse
Unit () 不带任何意义的值类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val x = 0x2F		// 16进制
val x = 41 // 10进制
val x = 041 // 8进制

val f = 3.14F
val f = 3.14f // `Float`浮点
val d = 3.14
val d = 0.314e1 // `Double`

val c = 'A'
val c = '\u0022'
val c = '\"' // `Char类型`

val str = "\"hello, world\"" // 字符串
val str = """"hello, world"""" // 忽略转义

var x = true
  • Unit()在概念上与Tuple0()相同(均唯一单例值) (但Tuple0类型不存在???)

Tuples

元组:不同类型值的聚集,可将不同类型的值放在同一个变量中保存

  • 元组包含一系列类:Tuple2Tuple3直到Tuple22

    • 创建包含n个元素的元组时,就是从中实例化相应类,用 组成元素的类型进行参数化
  • 特点

    • 比较:按值(内容)比较
    • 输出:输出括号包括的内容
  • 访问元素

    • <tuple>._<n>:访问元组中第n个元素(从1开始)
    • 元组支持模式匹配[解构]
  • 用途

    • 需要从函数中返回多个值
1
2
3
4
5
6
7
8
val t3 = ("hello", 1, 3.14)
val (str, i, d) = t3
// 必须括号包裹,否则三个变量被赋同值
println(t3._1)

val t2 = (1, 3)
val t22 = 1 -> 3
// `->`同样可以用于创建元组
  • 基于内容的比较衍生出模式匹配提取
  • 如果元素具有更多含义选择case class,否则选择元组

Symbol

符号类型:起标识作用,在模式匹配、内容判断中常用

  • 特点
    • 比较:按内容比较
    • 输出:原样输出
1
2
val s: Symbol = 'start
if (s == 'start) println("start......")

运算符号

  • 任何具有单个参数的方法都可以用作中缀运算符,而运算符 (狭义)就是普通方法

    • 可以使用点号调用
    • 可以像普通方法一样定义运算符
      1
      2
      3
      4
      case class Vec(val x: Double, val y: Double){
      def +(that: Vec) =
      new Vec(this.x + that.x, this.y + that.y)
      }
  • 表达式中运算符优先级:根据运算符第一个字符评估优先级

    • 其他未列出字符
    • */%
    • +-
    • :
    • +!
    • <>
    • &
    • ^
    • |
    • 所有字母:[a-zA-Z]

数值运算

  • 四则运算

    • +
    • -
    • *
    • /
    • %
  • 按位

    • &|^~
    • >>/<<:有符号移位
    • >>>/<<<:无符号移位
  • 比较运算

  • ><<=>=
  • ==/equals:基于内容比较
  • eq:基于引用比较

  • 逻辑运算

    • ||&&

字符串运算

  • Scala中String实际就是Java中java.lang.String类型
    • 可调用Java中String所有方法
    • 并定义有将String转换为StingOps类型的隐式转换函数 ,可用某某些额外方法
  • indexOf(<idx>)
  • toUppercasetoLowercase
  • reverse
  • drop(<idx>)
  • slice<<start>,<end>>
  • .r:字符串转换为正则表达式对象

类型推断

  • 编译器通常可以推断出

    • 表达式类型:工作原理类似推断方法返回值类型
    • 非递归方法的返回值类型
    • 多态方法、泛型类中泛型参数类型
  • 编译器不推断方法的形参类型

    • 但某些情况下,编译器可以推断作为参数传递的匿名函数 形参类型
  • 不应该依赖类型推断场合

    • 公开可访问API成员应该具有显式类型声明以增加可读性
    • 避免类型推断推断类型太具体

      1
      2
      var obj = null
      // 被推断为为`Null`类型仅有单例值,不能再分配其他值

类型别名

类型别名:具体类型别名

1
2
// 泛型参数必须指定具体类型
type JHashMap = java.util.HashMap[String, String]

Code Blocks

代码块:使用{}包围的表达式组合

  • 代码块中最后表达式的结果作为整个代码块的结果
    • Scala建议使用纯函数,函数不应该有副作用
    • 所以其中基本应该没有语句概念,所有代码块均可视为 表达式,用于赋值语句
  • {}:允许换行的(),Scala中{}基本同()

控制表达式

if语句

1
2
3
4
5
6
7
if(<eva_expr>){
// code-block if true
}else if(<eva_expr>){
// code-block
}else{
// code-block if false
}
  • 返回值:对应函数块返回值

while语句

1
2
3
while(<eva_expr>){
// code-block if true
}
  • Scala中while作用被弱化、不推荐使用
  • 返回值:始终为Unit类型()

for语句

1
2
3
4
5
6
7
for{
<item1> <- <iter1>
<item2> <- <iter2>
if <filter_exp>
if <filter_exp>
}{
}
  • 以上在同语句中多个迭代表达式等价于嵌套for
  • 返回值
    • 默认返回Unit类型()
    • 配合yield返回值迭代器(元素会被消耗)
  • 注意:迭代器中元素会被消耗,大部分情况不应该直接在嵌套 for语句中使用

match模式匹配

  • 模式匹配的候选模式

    • 常量
    • 构造函数:解构对象
      • 需伴生对象实现有unapply方法,如:case class
    • 序列
      • 需要类伴生对象实现有unapplySeq方法,如: Seq[+A]类、及其子类
    • 元组
    • 类型:适合需要对不同类型对象需要调用不同方法
      • 一般使用类型首字母作为case标识符name
      • 对密封类,无需匹配其他任意情况的case
      • 不匹配可以隐式转换的类型
    • 变量绑定
  • 候选模式可以增加pattern guards以更灵活的控制程序

  • 模式匹配可以视为解构已有值,将解构结果map至给定名称

    • 可以用于普通赋值语句中用于解构模式
    • 显然也适合于for语句中模式匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<target> match {
// 常量模式 + 守卫语句
case x if x % 2 == 0 =>
// 构造函数模式
case Dog(a, b) =>
// 序列模式
case Array(_, second) =>
// 元组模式
case (second, _*) =>
// 类型模式
case str: String =>
// 变量绑定
case all@Dog(name, _) =>
}

// 普通赋值语句中模式匹配
val all@Array(head, _*) = Array(1,3,3)
  • 可在普通类伴生对象中实现unapplyunapplySeq实现模式 匹配,此单例对象称为extractor objects

unapply

unapply方法:接受实例对象、返回创建其所用的参数

  • 构造模式依靠类伴生对象中unapply实现
  • unapply方法返回值应该符合
    • 若用于判断真假,可以返回Boolean类型值
    • 若用于提取单个T类型的值,可以返回Option[T]
    • 若需要提取多个类型的值,可以将其放在可选元组 Option[(T1, T2, ..., Tn)]
  • case class默认实现有此方法
1
2
3
4
5
6
7
8
class Dog(val name: String, val age: Int){
// 伴生对象中定义`unapply`方法解构对象
object Dog{
def unapply(dog: Dog): Option[(String, Int)]{
if (dog!=null) Some(dog.name, dog.age)
else None
}
}

unapplySeq

unapplySeq方法:接受实例对象、返回创建其所用的序列

  • 序列模式依靠类伴生对象中unapplySeq实现
  • 方法应返回Option[Seq[T]]
  • Seq[A+]默认实现此方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// `scala.Array`伴生对象定义
object Array extends FallbackArrayBuilding{
def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for(x <- xs.iterator) {
array(i) = x
i += 1
}
array
}
def apply[x: Boolean, xs: Boolean*]: Array[Boolean] = {
val array = new Array[Boolean](xs.length + 1)
array(0) = x
var i = 1
for(x <- xs.iterator){
array(i) = x
i += 1
}
array
}
/* 省略其它`apply`方法 */
def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
if(x == null) None
else Some(x.toIndexedSeq)
}

正则表达式模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import scala.util.matching.{Regex, MatchIterator}
// `.r`方法将字符串转换为正则表达式
val dateP = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
val dateP = new Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""")

// 利用`Regex`的`unapplySeq`实现模式匹配
// 不过此应该是定义在`Regex`类而不是伴生对象中
for(date <- dateP.findAllIn("2015-12-31 2016-01-01")){
date match {
case dateRegex(year, month, day) =>
case _ =>
}
}
// `for`语句中模式匹配
for(dateP(year, month, day) <- dateP.findAllIn("2015-12-31 2016-01-01")){
}
  • scala.util.matching具体参见cs_java/scala/stdlib

Functions

函数:带有参数的表达式

1
2
3
4
5
// 带一个参数的匿名函数,一般用作高阶函数参数
Array(1,2,3).map((x: Int) => x + 1)
Array(1,2,3).map(_+1) // 简化写法
// 具名函数
val fx: Float => Int = (x: Float) => x.toInt
  • 函数结构

    • 可以带有多个参数、不带参数
    • 无法显式声明返回值类型
  • 函数可以类似普通常量使用lazy修饰,当函数被使用时才会被 创建

  • 作高阶函数参数时可简化

    • 参数类型可推断、可被省略
    • 仅有一个参数,可省略参数周围括号
    • 仅有一个参数,可使用占位符_替代参数声明整体
  • Java:函数被编译为内部类,使用时被创建为对象、赋值给相应 变量
  • Scala中函数是“一等公民”,允许定义高阶函数、方法
    • 可以传入对象方法作为高阶函数的参数,Scala编译器会将 方法强制转换为函数
    • 使用高阶函数利于减少冗余代码

函数类型

函数类型:Scala中有Funtion<N>[T1, T2, ..., TN+1]共22种函数 类型,最后泛型参数为返回值类型

1
2
3
4
5
// 实例化`Function2[T1, T2, T3]`创建函数
val sum = new Function2[Int, Int, Int] {
def apply(x: Int, y: Int): Int = x + y
}
val sum = (x: Int, y: Int) => x + y

偏函数

偏函数:只处理参数定义域中子集,子集之外参数抛出异常

1
2
3
4
5
6
7
8
9
10
11
// scala中定义
trait PartialFunction[-A, +B] extends (A => B){
// 判断元素在偏函数处理范围内
def isDefinedAt(?ele: A)
// 组合多个偏函数
def orElse(?pf: PartialFunction[A, B])
// 方法的连续调用
def addThen(?pf: PartialFunction[A, B])
// 匹配则调用、否则调用回调函数
def applyOrElse(?ele: A, ?callback: Function1[B, Any])
}
  • 偏函数实现了Function1特质
  • 用途
    • 适合作为map函数参数,利用模式匹配简化代码
1
2
3
4
5
val receive: PartialFunction[Any, Unit] = {
case x: Int => println("Int type")
case x: String => println("String type")
case _ => println("other type")
}

Methods

方法:表现、行为类似函数,但有关键差别

  • def定义方法,包括方法名、参数列表、返回类型、方法体

  • 方法可以接受多个参数列表、没有参数列表

    1
    2
    3
    def addThenMutltiply(x: Int, y: Int)(multiplier: Int): Int = (x+y) * multiplier

    def name: String = System.getProperty("user.name")
  • Scala中可以嵌套定义方法

  • Java中全在类内,确实都是方法

Currying

柯里化:使用较少的参数列表调用多参数列表方法时会产生新函数, 该函数接受剩余参数列表作为其参数

  • 多参数列表/参数分段有更复杂的调用语法,适用场景
    • 给定部分参数列表
      • 可以尽可能利用类型推断,简化代码
      • 创建新函数,复用代码
    • 指定参数列表中部分参数为implicit
1
2
3
4
5
6
7
8
val number = List(1,2,3,4,5,6,7,8,9)
numbers.foldLeft(0)(_ + _)
// 柯里化生成新函数
val numberFunc = numbers.foldLeft(List[Int]())_
val square = numberFunc((xs, x) => xs:+ x*x)
val cube = numberFunc((xs, x) => xs:+ x*x*x)

def execute(arg: Int)(implicit ec: ExecutionContext)

隐式转换

隐式转换:编译器发现类型不匹配时,在作用域范围内查找能够转换 类型的隐式转换

  • 类型S到类型T的隐式转换由S => T类型函数的隐式值、 或可以转换为所需值的隐式方法定义

    • 隐式转换只与源类型、目标类型有关
    • 源类型到目标类型的隐式转换只会进行一次
    • 若作用域中有多个隐式转换,编译器将报错
  • 适用场合:以下情况将搜索隐式转换

    • 隐式转换函数、类:表达式e的类型S不符合期望类型 T
    • 隐式参数列表、值:表达式e类型S没有声明被访问的 成员m
  • 隐式转换可能会导致陷阱,编译器会在编译隐式转换定义时发出 警告,可以如下关闭警告

    • import scala.language.implicitConversions到隐式 转换上下文范围内
    • 启用编译器选项-language: implicitConversions
1
2
3
4
5
6
7
8
import scala.language.implicitCoversions

// `scala.Predef`中定义有
// 隐式转换函数
implicit def int2Integer(x: Int) =
java.lang.Integer.valueOf(x)
// 隐式参数列表
@inline def implicitly[T](implicit e:T) = e

隐式转换函数、类

1
2
3
4
5
6
7
8
9
10
11
// 隐式转换函数
implicit def float2int(x: Float) = x.toInt

// 隐式类
implicit class Dog(val name: String){
def bark = println(s"$name is barking")
}
"Tom".bark

// 隐式类最终被翻译为
implicit def string2Dog(name: String): Dog = new Dog(name)
  • 隐式类通过隐式转换函数实现
    • 其主构造函数参数有且只有一个
    • 代码更简洁、晦涩,类和方法绑定

隐式值、参数列表

  • 若参数列表中参数没正常传递,Scala将尝试自动传递 正确类型的隐式值

  • 查找隐式参数的位置

    • 调用包含隐式参数列表的方法时,首先查找可以直接访问、 无前缀的隐式定义、隐式参数
    • 在伴生对象中查找与隐式候选类型相关的、有隐式标记的 成员
  • 说明

    • 隐式值不能是顶级值
    • implicit能且只能作用于最后参数列表
    • 方法才能包含隐式参数列表,函数不可
    • 包含隐式参数列表方法不可偏函数化
  • 例1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    abstract class Monoid[A]{
    def add(x: A, y: A): A
    def unit: A
    }
    object ImplicitTest{
    // `implicit`声明该匿名类对象为隐式值
    implicit val stringMonoid: Monoid[String] = new Monoid[String]{
    def add(x: String, y: String): Strinng = x concat y
    def unit: String = ""
    }
    implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
    }

    // 定义隐式参数列表
    def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))

    def main(args: Array[String]): Unit = {
    println(sum(List(1,2,3)))
    println(sum(List("a", "b", "c")))
    }
    }
  • 例2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    trait Multiplicable[T] {
    def multiply(x: T): T
    }
    // 定义隐式单例对象
    implicit object MultiplicableInt extends Multiplicable[Int]{
    def multiply(x: Int) = x*x
    }
    implicit object MultiplicableString extends Mulitplicable[String]{
    def multiply(x: String) = x*2
    }
    // `T: Multiplicable`限定作用域存在相应隐式对象、或隐式值
    def multiply[T: Multiplicable](x: T) = {
    // 调用`implicitly`返回隐式对象、或隐式值
    val ev = implicitly[Multiplcable[T]]
    ev.multiply(x)
    }
    println(multiply(5))
    println(multiply(5))

传名参数

传名参数:仅在被使用时触发实际参数的求值运算

1
2
def calculate(input: => Int) = input * 37
// 在参数类型前加上`=>`将普通(传值)参数变为传名参数
  • 传名参数
    • 若在函数体中未被使用,则不会对其求值
    • 若参数是计算密集、长时运算的代码块,延迟计算能力可以 帮助提高性能
  • 传值参数:仅被计算一次

传名参数实现while循环

1
2
3
4
5
6
7
8
9
10
11
def whileLoop(condition: => Boolean)(body: => Unit): Unit =
if(condition){
body
whileLoop(condition)(body)
}

var i = 2
whileLoop(i > 0){
println(i)
i -= 1
}

默认参数

默认参数:调用时可以忽略具有默认值的参数

  • 调用时忽略前置参数时,其他参数必须带名传递
  • 跳过前置可选参数传参必须带名传参
  • Java中可以通过剔除可选参数的重载方法实现同样效果
  • Java代码中调用时,Scala中默认参数必须、不能使用命名参数

命名参数调用

  • 调用方法时,实际参数可以通过其对应形参名标记
    • 命名参数顺序可以打乱
    • 未命名参数需要按照方法签名中形参顺序放在前面

Exception

异常处理:try{throw...}catch{case...}抛出捕获异常

1
2
3
4
5
6
7
8
9
10
def main(args: Array[String]){
try{
val fp = new FileReader("Input")
}catch{
case ex: FileNotFoundException => println("File Missing")
case ex: IOException => println("IO Exception")
}finally{
println("finally")
}
}

Special Methods

综述

特殊方法:python类中具有特殊名称的方法,实现由特殊语法 所引发的特定操作

  • python实现操作符重载的方式

    • 允许每个类自行定义基于操作符的特定行为
    • 特定操作包括python内置的钩子函数
  • 钩子函数不能简单的看作直接调用特殊方法

    • 尝试调用备用实现:iterreversed
    • 修改方法返回值:dir
  • 大部分情况下,若没有定义适当方法,尝试执行操作raise AttributeErrorraise TypeError

    • __hash____iter____reversed____contains__等方法即使未定义,其对应钩子函数 实现会尝试调用可能的其他方法完成操作 (直接obj.__xxx__调用方法仍然报错)

    • 将特殊方法设为None表示对应操作不可用,此时即使以上 hashiterreversedin等操作也不会尝试调用 备用方法

实例创建、销毁

调用类时,元属性方法执行顺序

  • __prepare__():创建命名空间
  • 依次执行类定义语句
  • __new__():创建类实例
  • __init__():初始化类
    • __new__返回的新实例__init__方法将被调用
    • 用户定义__new__返回对象不一定期望类实例,调用的 __init__随之不一定是期望方法
  • 返回__new__返回类实例

__prepare__

  • 在所有类定义开始执行前被调用,用于创建类命名空间
  • 一般这个方法只是简单的返回一个字典或其他映射对象

__new__

1
2
classmethod object.__new__(cls[, *args, **kwargs]):
pass
  • 用途:创建、返回cls类新实例

    • super().__new__(cls[,...])调用超类方法创建类实例, 然后根据需要修改新创建实例再返回
  • 参数

    • cls:待实例化类
    • 其余参数:类构造器表达式参数
  • 返回值:cls类新实例

    • __new__返回值就是类构造器的返回值,有绝对控制权

说明

  • __new__builtin_function_or_method

  • __new__是静态方法:以需实例化类作为第一个参数

    • __new__方法绑定当前类对象
    • 特例,不需要显式声明为静态方法
  • 原生有两个__new__函数,二者C实现不同

    • type.__new__:元类继承,用于创建类对象
    • object.__new__:其他类继承,用于创建实例

__init__

1
2
def object.__init__(self[, *args, *kwargs]):
pass
  • 用途:初始化类实例

    • 类构造器中__new__返回类实例调用此方法初始化
    • 若基类有用户定义__init__方法,则其派生类__init__ 应该显式调用基类__init__保证基类部分正确初始化
  • 参数

    • self:当前类实例
    • 其余参数:类构造器表达式参数
  • 返回值:None,否则raise TypeError

__del__

1
def object.__del__(self)
  • 用途:实例销毁时(引用计数变为0)被调用
    • 若基类有__del__方法,则其派生类__del__方法中 需要显式调用基类__del__保证基类部分正确清除
    • 对象重生:在其中创建该实例的新引用推迟其销毁
      • 不推荐
      • 重生对象被销毁时__del__是否会被再次调用取决于 具体实现
      • 当前CPython实现中只会调用一次

说明

  • 解释器退出时不会确保为仍然存在的对象调用__del__方法
  • “钩子函数”:del
    • del x不直接调用x.__del__()
    • del x仅将x的引用计数减一

输出属性

__repr__

1
2
def object.__repr__(self):
pass
  • 用途:输出对象的“官方”字符串表示

    • 如果可能,应类似有效的python表达式,可以用于重建具有 相同取值的对象(适当环境下)
    • 若不可能,返回形如<...some useful description...> 的字符串
    • 常用于调试,确保内容丰富、信息无歧义很重要
  • 返回值:字符对象

    • 内置钩子函数:repr
    • 交互环境下直接“执行”变量的结果

__str__

1
2
def object.__str__(self):
pass
  • 用途:生成对象“非正式”、格式良好的字符串表示

    • 返回较方便、准确的描述信息
  • 返回值:字符串对象

    • 内置钩子函数:str

说明

  • object.__str__方法默认实现调用object.__repr__

    • 所以若未定义__str__,需要实例“非正式”字符串表示时 也会使用__repr__
  • formatprint函数会隐式调用对象__str__方法

    • 此时若__str__返回非字符串会raise TypeError

__bytes__

1
2
def object.__bytes__(self):
pass
  • 用途:生成对象的字节串表示

  • 返回值:bytes对象

    • 内置钩子函数:bytes

__format__

1
def object.__format__(self, format_spec)
  • 用途:生成对象的“格式化”字符串表示

    • 内部常调用formatstr.format实现格式化
    • object.__format__(x, '')等同于str(x)
  • 参数

    • fomrat_spec:包含所需格式选项描述的字符串
      • 参数解读由实现__format__的类型决定
      • 大多数类将格式化委托给内置类型、或使用相似格式化 语法
  • 返回值:字符串对象

    • 内置钩子函数:format

__hash__

1
2
def object.__hash__(self):
pass
  • 用途:计算对象hash值返回

    • 相等的对象(即使类型不同)理应具有相同hash值
    • 建议把参与比较的对象的全部组件的hash值打包为元组, 对元组做hash运算
      1
      2
      def __hash__(self):
      return hash((self.name, self.nick, self.color))
  • 返回值:整数

    • 内置钩子函数:hash()

说明

  • hash()会从对象自定义的__hash__()方法返回值中截断为 Py_ssize_t大小

    • 64bits编译平台通常为8bytes、32bits为4bytes
    • 若对象__hash__()需要在不同位大小的平台上互操作, 需要检查支持的平台位宽
    • 查看sys.hash_info.width
  • setfrozensetdict这3个hash集类型中成员的操作 会调用相应__hash__()

  • 类的__hash__方法设置为None

    • 尝试获取实例hash值时将raise TypeError
    • isinstance(obj, collecitons.abc.Hashable)返回 False
    • 单纯在__hash__中显式raise TypeError会被错误 认为是可hash

关联__eq__

hash绝大部分应用场景是比较是否相等,所以__hash____eq__ 密切相关

  • 类未定义__eq__

    • 也不应该定义__hash__,单独hash结果无法保证比较结果
  • 类实现__eq__

    • 未定义__hash__:其实例将不可被用作hash集类型的项
    • 类中定义了可变对象:不应该实现__hash__,因为hash集 实现要求键hash值不可变
  • 类重载__eq__方法

    • 默认其__hash__被隐式设为None
    • 否则须设置__has__ = <ParentClass>.__hash__显式保留 来自父类__hash__实现

默认实现

  • floatintegerdecimal.Decimal等数字类型hash运算 是基于为任意有理数定义的统一数学函数

  • strbytesdatetime对象__hash__值会使用不可预知 值随机加盐

    • 盐在单独python进程中保持不变,但在重复执行的python 进程之间是不可预测的
    • 目的是为了防止某种形式的DDos服务攻击
  • 改变hash值会影响集合迭代次序

    • python也不保证次序不会改变

__bool__

1
2
def object.__bool__(self):
pass
  • 用途:返回TrueFalse实现真值检测

    • 未定义:调用__len__返回非0值时对象逻辑为真
    • __len____bool__均未定义:所有实例逻辑为真
  • 返回值:FalseTrue

    • 内置构造函数:bool()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Pair:
def __init__(self, x, y):
self.x = x
self.y = y

def __repr__(self):
# 返回实例代码表示形式
# 通常用于重新构造实例
return "Pair({0.x!r}, {0.y!r})".format(self)
# 格式化代码`!r`指明输出使用`__repr__`而不是默认
# 的`__str___`
# 格式化代码`0.x`表示第一个参数`x`属性

def __str__(self):
return "({0.x!s}, {0.y!s})".format(self)
# 格式化代码`!s`指明使用默认`__str__`

def __format__(self):
if self.x == 0:
return self.y
elif self.y == 0:
return self.x
return "{0.x!r}, {0.y!r}".format(self)

Rich Comparison Methods

富比较方法

1
2
3
4
5
6
7
8
9
10
11
12
def object.__lt__(self, other):
pass
def object.__le__(self, other):
pass
def object.__eq__(self, other):
pass
def object.__ne__(self, other):
pass
def object.__gt__(self, other):
pass
def object.__ge__(self, other):
pass
  • 用途:比较运算符重载

    • x < y:调用x.__lt__(y)
    • x <= y:调用x.__le__(y)
    • x == y:调用x.__eq__(y)
    • x != y:调用x.__ne__(y)
  • 返回值

    • 成功比较返回FalseTrue
    • 若指定方法没有相应实现,富比较方法会返回单例对象 NotImplemented
  • 比较运算默认实现参见cs_python/py3ref/expressions

说明

  • 默认情况下,__ne__会委托给__eq__,并将结果取反,除非 结果为NotImplemented

  • 比较运算符之间没有其他隐含关系

    • x < y or x == y为真不意味着x <= y
    • 要根据单个运算自动生成排序操作可以利用 functools.total_ordering()装饰器简化实现
  • 以上方法没有对调参数版本(左边参数不支持该操作,右边参数 支持该操作)

    • 若两个操作数类型不同、且右操作数是左操作数直接或间接 子类,优先选择右操作数的反射方法,否则左操作数 方法(不考虑虚拟子类)
    • 反射方法
      • __lt____gt__互为反射
      • __le____ge__互为反射
      • __eq____ne__各为自身反射

内部信息

__dict__

  • 钩子函数:varsdir(部分)

    • vars是真正对应的钩子函数,返回键值对
    • dir执行过程中会访问__dict____class__,而且 只返回keys
  • 对象底层字典,存储对象属性、方法

    • 注意区分开:实例属性、类属性、基类属性,__dict__ 只包括当前实例属性、方法
    • 返回结果是dir结果的子集
  • 调用实例obj的属性时,按照以下顺序查找

    • obj.__dict__:当前实例的__dict__
    • type(obj).__dict__:实例所属类的__dict__
    • type(obj).mro().__dict__:基类的__dict__
  • 在大部分情况下__dict__会自动更新,如setattr函数时, 或说实例的属性、方法更新就是__dict__的变动

    • 一般情况下不要直接访问__dict__,除非真的清楚所有 细节,如果类使用了cls.__slots__@property、 描述器类等高级技术时代码可能会被破坏

    • 尽量使用setattr函数,让python控制其更新

__class__

  • 用途:返回实例所属类

  • 返回值:实例(狭义)返回类、类返回元类

    • 钩子函数:type

__objclass__

  • 用途:被inspect模块解读为指定实例所在的类
    • 合适的设置可以有助于动态类属性的运行时检查
    • 对于可调用对象:指明第一个位置参数应为特定类型的 实例、子类
      • 描述器类:instance参数

        todo

__slots__

  • 用途:显式声明数据成员、特征属性,限制实例添加属性

    • 可赋值为:字符串、可迭代对象、实例使用的变量名构成的 字符串序列

      • 可迭代对象中元素可以是任何类型
      • 还可以映射类型,未来可能会分别赋给每个键特殊含义 的值
    • __slots__会为已声明变量保留空间

      • 直接访问将raise AttributeError
      • dir可以找到__slots__中声明的变量
  • 阻止默认为每个实例创建__dict____weakref__的 行为,除非在__slots__中显式声明、或在父类中可用

    • __dict__属性实例无法给未在__slots__中列出 的新变量赋值

      • 但是python很多特性依赖于普通的依赖字典实现,定义 __slots__的类不再支持普通类某些特性
      • 大多数情况下,应该只在经常使用到作为数据结构的 类上定义__slots__
      • 不应该把__slots__作为防止用户给实例增加新属性 的封装工具
    • __weakref__属性实例不支持对实例的弱引用

  • 是阻止给实例创建__dict__,类本身仍然有__dict__属性 (dir返回值中无__dict____dir__返回值中有)

说明

  • __slots__声明的行为不只限于定义其的类

    • 父类中声明__slots__可以在子类中使用,但子类将获得 __dict____weakref__,除非其也定义了__slots__

    • 子类__slots__中定义的slot将覆盖父类中同名slot

      • 需要直接从基类直接获取描述器才能访问
      • 这会导致程序未定义,以后增加检查避免
    • 多重继承中只允许一个父类具有非空__slots__,否则 raise TypeError

  • __slots__是在类层次上的实现:为每个变量创建描述器

    • 类属性不能被用于给在__slots__中定义变量设置默认值
    • 否则类属性会覆盖描述器赋值,变成只读属性
  • 非空的__slots__不适用于派生自“可变长度”内置类型,如 intbytestuple

  • 定义类属性__slots__后,python会为实例属性使用紧凑内部 表示

    • 实例属性使用固定大小、很小的数组构建,而不是为每个 实例定义字典
    • __slots__列出的属性名在内部映射到数组指定下标上
    • 类似于R中factor类型、C中enum类型
    • 相比__dict__可以显著节省空间、提升属性查找速度
1
2
3
4
5
6
class Date:
__slots__ = ["year", "month", "day"]
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
  • 继承自未定义__slots__类时,实例中__dict____weakref__属性将总是可访问的

  • __class__赋值仅在两个类具有相同__slots__值时才有用

自定义属性访问

__getattr__

1
2
def object.__getattr__(self, name):
pass
  • 用途:.默认属性访问引发AttributeError而失败时调用

    • 如果属性通过正常机制找到,__getattr__不会被调用
      • __getattr____setattr__之间故意设置的 不对称性
      • 出于效率考虑
    • 对实例变量而言,无需在实例属性字典中插入值,就可以 模拟对其的完全控制
  • 返回值:计算后的属性值、或raise AttributeError

说明

  • 可能引发AttributeError

    • 调用__getattribute__时因为name不是实例属性、 或是类关系树中属性
    • 对调用__get__获取name描述器
  • 调用__getattr__.运算符中逻辑

    • __getattribute__显式调用raise AtttributeError 不会调用__getattr__
  • __getattr__甚至不是object具有的 <wrapper_descriptor>

  • 相较于__getattribute__其实更常用,因为修改所有对 对对象的访问逻辑没啥价值

__getattribute__

1
2
3
4
5
6
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, "__get__"):
return v.__get__(None, self)
return v
  • 用途:访问对象属性时无条件被调用

    • 判断访问属性类型、做对应操作
      • 描述器:调用描述器方法
      • 实例方法:为类中函数绑定实例
      • 类方法:为类中函数绑定类
      • 静态方法:不绑定
      • 普通属性
    • 作为通过特定语法、内置函数隐式调用的结果情况下, 查找特殊方法时仍可能被跳过
  • 返回值:找到的属性值、或raise AttributeError

  • __getattribute__仅对继承自object的新式类实例可用

说明

  • 内置类型均有各自__getattribute__函数实例

    • 其均为wrapper_descriptor类型(C实现的函数)
    • 各函数实例标识符不同,若其均“继承自object”,其 应为同一个函数实例
    • 自定义类真继承自object类,其__getattribute__object.__getattribute__
  • 自定义实现

    • 避免方法中无限递归,实现总应该调用具有相同名称 基类方法访问所需要的属性

钩子函数

  • .运算符:首先调用__getattribute__,若无访问结果, 调用__getattr__

    • .运算符说明参见cs_python/py3ref/cls_basics
  • getattr:基本同.运算符,除可捕获异常,设置默认返回值

  • hasattr:内部调用getattr,根据raise Exception判断 属性是否存在

    • 可以通过@property.getterraise AttributeError 使得属性看起来不存在
    • 内部有更多boilerplate相较于getattr更慢
    • 则按照字面意思使用不需要考虑过多

__setattr__

1
2
def object.__setattr__(self, name, value):
pass
  • 用途:属性被尝试赋值时被调用

    • 默认实现:将值保存到实例字典
    • __setattr__要赋值给实例属性,应该调用同名基类 方法
  • 返回指:None

    • 钩子函数:setattr

__delattr__

1
2
def object.__delattr__(self, name):
pass
  • 用途:删除实例属性时被调用

    • 默认实现:从实例字典中删除对应项
    • 应该在del obj.name对该对象有意义时才实现
  • 返回值:None

    • 内置钩子函数:delattrdel

__dir__

1
2
def object.__dir__(self):
pass
  • 用途:返回实例中“可访问”名称的字符串列表

    • 默认实现:返回实例、类、祖先类所有属性
    • 交互式解释器就是在__dir__/dir返回列表中进行查询 进行补全
  • 返回值:序列

    • 内置钩子函数:dir
      • dir()获取__dir__返回序列,转换为列表、排序
      • dir()会剔除__dir__返回值中部分值
      • __dir__返回值不可迭代,报错

自定义模块属性访问

  • __getattr____dir__可以用于自定义对模块属性的访问

    • 模块层次__getattr__类似普通类
      • 接受属性名作为参数
      • 返回计算后结果、或raise AttributeError
      • 若正常查找__getattribute__无法在模块中找到某个 属性,调用__getattr__
    • 模块层次__dir__类似普通类
      • 不接受参数
      • 返回模块中可访问名称的字符串列表
  • 可以将模块的__class__属性设置为types.ModuleType子类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import sys
    import types import ModuleType

    class VersboseModule(ModuleType):
    def __repr__(self):
    return f"verbose {self.__name__}"
    def __setattr__(self, attr, value):
    print(f"settting {attr}")
    super().__setattr__(attr, value)

    sys.modules[__name__].__class__ = VerboseModule
  • 设置模块__getattr____class__只影响使用属性访问 语法进行查找,直接访问模块全局变量(通过模块内代码、对 模块全局字典引用)不受影响

描述器类

描述器:具有“绑定行为”的对象属性

  • 类中定义其中任意一个方法,则其实例被称为描述器

    • __set__
    • __get__
    • __delete__
  • 所有对描述器属性的访问会被__get____set____delete__方法捕获/重载

    • 如果只是想简单的自定义某个类的属性处理逻辑,使用 @porperty装饰器简化实现
  • @property参见cs_python/py3ref/cls_basics

描述器协议

  • 以下方法仅包含其的类的实例出现在类属性中才有效
    • 即以下方法必须在(祖先)类__dict__中出现,而不是 实例__dict__
    • 即描述器只能定义为类属性,不能定义为实例属性

__get__

1
2
def object.__get__(self, instance, owner=None):
pass
  • 用途:访问描述器属性时调用,重载实例属性访问

    • 若描述器未定义__get__,则访问属性会返回描述器对象 自身,除非实例字典__dict__中有同名属性
    • 若仅仅只是从底层实例字典中获取属性值,__get__方法 不用实现
  • 参数

    • instance:用于方法属性的实例
    • owner:实例所属类,若通过类获取属性则为None
  • 返回值:计算后属性值、或raise AttributeError

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def __get__(self, instance, cls):
    if instance is None:
    # 装饰器类一般作为类属性,需要考虑通过类直接访问
    # 描述器类属性,此时`instance is None`
    # 常用操作是返回当前实例
    return self
    else:
    return instance.__dict__[self.name]

    # self:描述器类当前实例
    # instance:定义描述器作为类属性的类的实例
    # cls:定义描述器作为类属性的类

__set__

1
2
def object.__set__(self, instance, name, value):
pass
  • 用途:设置实例instance的“描述器属性”值为value,重载 实例属性赋值

    • 常用实现:操作实例instance.__dict__存储值,使得 看起来是设置普通实例属性
  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def __set__(self, instance, name, value):
    if instance is None:
    pass
    else:
    if not instance(value, int):
    raise TypeError("expect an int")
    instance.__dict__[self.name] = value
    # 操作实例底层`__dict__`

    # `value`:赋给描述器类属性的值

__delete__

1
2
def object.__delete__(self, instance):
pass
  • 用于:“删除”实例instance的“描述器属性”,重载实例属性 删除

    • 具体实现应取决于__set__实现
  • 示例

    1
    2
    3
    4
    5
    6
    def __delete__(self, instance):
    if instance is None:
    pass
    else:
    del instance.__dict__[self.name]
    # 操作实例底层`__dict__`

__set_name__

1
2
def object.__set_name__(self, owner, name):
pass
  • 用途:类owner被创建时调用,描述器被赋给name

实现原理

  • 描述器的实现依赖于object.__getattribute__()方法

    • 可以通过重写类的__getattribute__方法改变、关闭 描述器行为
  • 描述器调用:描述器x定义在类A中、a = A()

    • 直接调用:x.__get__(a)
    • 实例绑定:a.x
      • 转换为:type(a).__dict__['x'].__get__(a)
    • 类绑定:A.x
      • 转换为:A.__dict__['x'].__get__(None,A)
    • 超绑定:super(a, A).x

实例绑定—资料描述器

  • 资料描述器:定义了__set____delete__方法
  • 非资料描述器:只定义了__get__方法
  • 访问对象属性时,描述器调用的优先级取决于描述器定义的方法

    • 优先级:资料描述器 > 实例字典属性 > 非资料描述器
    • 实例属性会重载非资料描述器
    • 实例属性和资料描述器同名时,优先访问描述器,否则优先 访问属性
  • 只读资料描述器:__set__raise AttributeError得到

描述器调用

todo

Python设计

  • function类中定义有__get__方法,则其实例(即函数) 都为非资料描述器

    • 所以实例可以覆盖、重载方法
    • __getattribute__会根据不同方法类型选择绑定对象
      • staticmethod:静态方法
      • classmethod:类方法
      • 实例方法
  • super类中定义有__get__方法,则其实例也为描述器

  • @property方法被实现为资料描述器

特殊描述器类

todo

  • wrapper_descripter<slot wrapper>,封装C实现的函数

    • 等价于CPython3中函数
    • 调用__get__绑定后得到<method-wrapper>
    • object的方法全是<slot wrapper>
  • method-wrapper<method-wrapper>,封装C实现的绑定方法

    • 等价于CPython3中绑定方法

function描述器类

function描述器类:实例化即得到函数

1
2
3
4
5
6
7
8
9
class function:
function(code, globals[, name[, argdefs[, closure]]])

def __call__(self, /, *args, **kwargs):
# 作为一个函数调用自身

def __get__(self, instance, owner, /):
# 返回`owner`类型实例`instance`的属性
# 即返回绑定方法

method描述器类

method描述器类:实例化即得到(bound )method,绑定方法

1
2
3
4
5
6
7
8
class method:
method(function, instance)

def __call__(self, /, *args, **kwargs):
# 作为函数调用自身

def __get__(self, instance, owner, /):
# 返回自身
  • (bound )method:绑定方法,(首个参数)绑定为具体实例 的函数,即实例属性

XXmethod描述类

  • 代码是C实现,这里是python模拟,和help结果不同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class classmethod:
def __init__(self, method):
self.method = method
def __get__(self, obj, cls):
return lambda *args, **kw: self.method(cls,*args,**kw)

class staticmethod:
def __init__(self, callable):
self.f = callable
def __get__(self, obj, cls=None):
return self.f
@property
def __func__(self):
return self.f
  • 类中静态方法、类方法就是以上类型的描述器

    • 静态方法:不自动传入第一个参数
    • 类方法:默认传递类作为第一个参数
    • 描述器用途就是避免默认传入实例为第一个参数的行为
  • 静态方法、类方法均是非资料描述器,所以和实例属性重名时 会被覆盖

  • 所以类静态方法、类方法不能直接通过__dict__获取、调用, 需要调用__get__方法返回绑定方法才能调用

    • 直接访问属性则由__getattribute__方法代劳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Integer:
# 描述器类
def __init__(self, name):
self.name = name

def __get__(self, instance, cls):
# 描述器的每个方法会接受一个操作实例`instance`
if instance is None:
# 描述器只能定义为类属性,在这里处理直接使用类
# 访问描述器类的逻辑
return self
else:
return instance.__dict__(self.name)

def __set__(self, instance, value):
if not instance(value, int):
rasie TypeError("expect an int")
instance.__dict__[self.name] = value
# 描述器方法会操作实例底层`__dict__`属性

def __delete__(self, instance):
del instance.__dict__[self.name]

class Point:
x = Integer("x")
y = Integer("y")
# 需要将描述器的实例作为类属性放在类的定义中使用

def __init__(self, x, y):
self.x = x
self.y = y

def test():
p = Point(2, 3)
print(p.x)
# 调用`Point.x.__get__(p, Point)`
print(Point.x)
# 调用`Point.x.__get__(None, Point)`
p.y = 5
# 调用`Point.y.__set__(p, 5)`

自定义类创建

__init_subclass__

1
2
classmethod object.__init_subclass__(cls):
pass
  • 用途:派生类继承父类时,基类的__init_subclas__被调用
    • 可以用于编写能够改变子类行为的类
    • 类似类装饰器,但是类装饰其影响其应用的类,而 __init_subclass__影响基类所有派生子类
    • 默认实现:无行为、只有一个参数cls
    • 方法默认、隐式为类方法,不需要classmethod封装
  • 参数

    • cls:指向新的子类
    • 默认实现无参数,可以覆盖为自定义参数
    1
    2
    3
    4
    5
    6
    7
    class Philosopher:
    def __init_subclass__(self, default_name, **kwargs):
    super().__init_subclass__(**kwrags)
    cls.default_name = default_name

    class AstraliaPhilosopher(Philosopher, default_name="Bruce"):
    pass
    • 定义派生类时需要注意传递参数
    • 元类参数metaclass会被其他类型机制消耗,不会被传递 给__init_subclass__

元类

  • 默认情况下,类使用type构建

    • 类体在新的命名空间中执行,类名被局部绑定到 元类创建结果type(name, bases, namespace)
  • 可在类定义部分传递metaclass关键字参数,自定义类创建 过程

    • 类继承同样继承父类元类参数
    • 其他类定义过程中的其他关键字参数会在以下元类操作中 进行传递
      • 解析MRO条目
      • 确定适当元类
      • 准备类命名空间__prepare__
      • 执行类主体
      • 创建类对象

解释MRO条目

1
2
def type.__mro_entries__():
pass
  • 用途:若类定义中基类不是type的实例,则使用此方法对 基类进行搜索

    • 找到结果时,以原始基类元组作为参数进行调用
  • 返回值:类的元组替代基类被使用

    • 元组可以为空,此时原始基类将被忽略

元类确定

  • 若没有显式给出基类、或元类,使用type()
  • 若显式给出的元类不是type()的实例,直接用其作为元类
  • 若显式给出type()实例作为元类、或定义有基类,则选取 “最派生”元类
    • 最派生元类从显式指定的元类、基类中元类中选取
    • 最派生元类应为所有候选元类的子类型
    • 若没有满足条件的候选元类则raise TypeError

准备类命名空间

1
2
def type.__prepare__(name, bases, **kwds):
pass
  • 用途:确定合适的元类之后,准备类命名空间

    • 若元类没有__prepare__属性,类命名空间将被初始化为 空ordered mapping
  • 参数:来自于类定义中的关键字参数

执行类定义主体

1
2
exec(body, globals(), namespace)
# 执行类主体类似于
  • 普通调用和exec()区别
    • 类定义在函数内部时
      • 词法作用域允许类主体、方法引用来自当前、外部 作用域名称
      • 但内部方法仍然无法看到在类作用域层次上名称
      • 类变量必须通过实例的第一个形参、类方法方法

创建类对象

1
2
metaclass(name, base, namespace, **kwds):
pass
  • 用途:执行类主体填充类命名空间后,将通过调用 metaclass(name, base, namespace, **kwds)创建类对象

  • 参数:来自类定义中的关键字参数

说明
  • 若类主体中有方法中引用__class__super,则__class__ 将被编译器创建为隐式闭包引用

    • 这使得无参数调用super可以能基于词法作用域正确 定位类
    • 而被用于进行当前调用的类、实例则是基于传递给方法 的第一个参数来标识

自定义实例、子类检查

  • 以下方法应该的定义在元类中,不能在类中定义为类方法

    • 类似于实例从类中查找方法
  • 元类abc.ABCMeta实现了以下方法以便允许将抽象基类ABC 作为“虚拟基类”添加到任何类、类型(包括内置类型)中

__instancecheck__

1
2
def class.__instancecheck__(self, instance):
pass
  • 用途:若instance被视为class直接、间接实例则返回真值

    • 重载instance内置函数行为
  • 返回:布尔值

    • 内置钩子函数:isintance(instance, class)

__subclasscheck__

1
2
class.__subclasscheck__(self, subclass):
pass
  • 用途:若subclass被视为class的直接、间解子类则返回 真值

    • 重载issubclass内置函数行为
  • 返回:布尔值

    • 内置钩子函数:issubclass(subclass, class)

模拟范型类型

__class_getitem__

1
2
classmethod object.__class_getitem__(cls, key):
pass
  • 用途:按照key指定类型返回表示泛型类的专门化对象

    • 实现PEP 484规定的泛型类语法
    • 查找基于对象自身
    • 主要被保留用于静态类型提示,不鼓励其他尝试使用
    • 方法默认、隐式为类方法,不需要classmethod封装
  • 参数

    • cls:当前类
    • key:类型

模拟可调用对象

__call__

1
2
def object.__call__(self[,args...]):
pass
  • 用途:实例作为函数被调用时被调用
    • 若定义此方法x(arg1, arg2, ...)等价于 x.__call__(arg1, args2, ...)

模拟容器类型

  • collections.abc.MutableMapping为抽象基类
    • 其实现基本方法集__getitem____setitem____delitem__keys()
    • 可以方法继承、扩展、实现自定义映射类

__len__

1
2
def object.__len__(self):
pass
  • 用途:计算、返回实例长度

    • 若对象未定义__bool__,以__len__是否返回非0作为 布尔运算结果
  • 返回值:非负整形

    • 钩子函数:len()
  • CPython:要求长度最大为sys.maxsize,否则某些特征可能 会raise OverflowError

__length_hint__

1
2
def object.__length_hist__(self):
pass
  • 用途:返回对象长度估计值

    • 存粹为优化性能,不要求正确无误
  • 返回值:非负整形

    • 钩子函数:operator.length_hint()

__getitem__

1
2
def object.__getitem__(self, key):
pass
  • 用途:实现根据索引取值

  • 参数

    • 序列key:整数、切片对象

      • key类型不正确将raise TypeError
      • key在实例有效范围外将raise IndexError
    • 映射key:可hash对象

      • key不存在将raise KeyError
  • 返回值:self[key]

__setitem__

1
2
def object.__setitem__(self, key, value):
pass
  • 用途:实现根据索引赋值

  • 参数:同__geitem__

__delitem__

1
2
def object.__delitem(self, key):
pass
  • 用途:实现删除索引对应项

  • 参数:同__getitem__

__missing__

1
2
def object.__missing__(self, key):
pass
  • 用途:__getitem__无法找到映射中键时调用

__reversed__

1
2
def object.__iter__(self):
pass
  • 用途:为容器类创建逆向迭代器

  • 返回值:逆向迭代对象

    • 内置钩子函数:reversed()

说明

  • 若未提供__reversed__方法,reversed函数将回退到使用 序列协议__len____getitem__

  • 支持序列协议的对象应该仅在能够提供比reversed更高效实现 时才提供__reversed__方法

__contains__

1
2
def object.__contains__(self, item):
pass
  • 用途:实现成员检测

    • itemself成员则返回True、否则返回False
    • 对映射应检查键
  • 返回值:布尔值

    • 钩子运算:in

说明

  • 若未提供__contains__方法,成员检测将依次尝试

    • 通过__iter__进行迭代
    • 使用__getitem__旧式序列迭代协议
  • 容器对象可以提供更有效率的实现

模拟数字

数字运算

定义以下方法即可模拟数字类型

  • 特定类型数值类型不支持的运算应保持未定义状态
  • 若不支持与提供的参数进行运算,应返回NotImplemented
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def object.__add__(self, other):
# `+`
def object.__sub__(self, other):
# `-`
def object.__mul__(self, other):
# `*`
def object.__matmul__(self, other):
# `@`
def object.__truediv__(self, other):
# `/`
def object.__floordiv__(self, other):
# `//`
def object.__mod__(self, other):
# `%`
def object.__divmod__(self, other):
# `divmod()`
def object.__pow__(self, other[, modulo=1]):
# `pow()`/`**`
# 若要支持三元版本内置`pow()`函数,应该接受可选的第三个
# 参数
def object.__lshift__(self, other):
# `<<`
def object.__rshift__(self, other):
# `>>`
def object.__and__(self, other):
# `&`
def object.__or__(self, other):
# `|`
def object.__xor__(self, other):
# `~`

反射二进制算术运算

以下成员函数仅在左操作数不支持相应运算且两操作数类型不同时被调用

  • 实例作为作为相应运算的右操作数

  • 若右操作数类型为左操作数类型子类,且字类提供如下反射方法

    • 右操作数反射方法优先于左操作数非反射方法被调用
    • 允许子类覆盖祖先类运算符
  • 三元版pow()不会尝试调用__rpow__(转换规则太复杂)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def object.__radd__(self, other):
# `+`
def object.__rsub__(self, other):
# `-`
def object.__rmul__(self, other):
# `*`
def object.__rmatmul__(self, other):
# `@`
def object.__rtruediv__(self, other):
# `/`
def object.__rfloordiv__(self, other):
# `//`
def object.__rmod__(self, other):
# `%`
def object.__rdivmod__(self, other):
# `divmod()`
def object.__rpow__(self, other[, modulo=1]):
# `pow()`/`**`
# 若要支持三元版本内置`pow()`函数,应该接受可选的第三个
# 参数
def object.__rlshift__(self, other):
# `<<`
def object.__rrshift__(self, other):
# `>>`
def object.__rand__(self, other):
# `&`
def object.__ror__(self, other):
# `|`
def object.__rxor__(self, other):
# `~`

扩展算术赋值

实现以下方法实现扩展算数赋值

  • 以下方法应该尝试对自身进行操作

    • 修改self、返回结果(不一定为self
  • 若方法未定义,相应扩展算数赋值将回退到普通方法中

  • 某些情况下,扩展赋值可导致未预期错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def object.__iadd__(self, other):
# `+=`
def object.__isub__(self, other):
# `-=`
def object.__imul__(self, other):
# `*=`
def object.__imatmul__(self, other):
# `@=`
def object.__itruediv__(self, other):
# `/=`
def object.__ifloordiv__(self, other):
# `//=`
def object.__imod__(self, other):
# `%=`
def object.__ipow__(self, other[, modulo=1]):
# `**=`
def object.__ilshift__(self, other):
# `<<=`
def object.__irshift__(self, other):
# `>>=`
def object.__iand__(self, other):
# `&=`
def object.__ior__(self, other):
# `|=`
def object.__ixor__(self, other):
# `~=`

一元算术运算

1
2
3
4
5
6
7
8
def object.__neg__(self):
# `-`
def object.__pos__(self):
# `+`
def object.__abs__(self):
# `abs()`
def object.__invert__(self):
# `~`

类型转换运算

1
2
3
4
5
6
def object.__complex__(self):
# `complex()`
def object.__int__(self):
# `int()`
def object.__float__(self):
# `float()`

整数

1
2
def object.__index__(self):
pass
  • 存在此方法表明对象属于整数类型

    • 必须返回整数
    • 为保证以一致性,同时也应该定义__int__(),两者返回 相同值
  • 调用此方法以实现operator.index()、或需要无损的转换为 整数对象

    • 作为索引、切片参数
    • 作为bin()hex()oct()函数参数

精度运算

1
2
3
4
5
6
7
8
def object.__round__(self[, ndigits]):
# `round()`
def object.__trunc__(self):
# `math.trunc()`
def object.__floor__(self):
# `math.floor()`
def object.__ceil__(self):
# `math.ceil()`
  • 返回值:除__round__中给出ndigits参数外,都应该为 原对象截断为Integral(通常为int

  • 若未定义__int__,则int回退到__trunc__

元属性查找

  • 元属性查找通常会绕过__getattribute__方法,甚至包括元类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Meta(type):
    def __getattribute__(*args):
    print("Metaclass getattribute invoked")
    return type.__getattribute__(*args)

    class C(object, metaclass=Meta):
    def __len__(self):
    return 10
    def __getattribute__(*args):
    print("Class getattribute invoked")
    return object.__geattribute__(*args)

    if __name__ == "__main__":
    c = C()
    c.__len__()
    # 通过实例显式调用
    # 输出`Class getattribute invoked\n10"
    type(c).__len__(c)
    # 通过类型显式调用
    # 输出`Metaclass getattribute invoked\n10"
    len(c)
    # 隐式查找
    # 输出`10`
    • 为解释器内部速度优化提供了显著空间
    • 但是牺牲了处理特殊元属性时的灵活性
      • 特殊元属性必须设置在类对象本身上以便始终一致地 由解释器发起调用
  • 隐式调用元属性仅保证元属性定义在对象类型中能正确发挥 作用

    1
    2
    3
    4
    5
    6
    7
    8
    class C:
    pass

    if __name__ == "__main__":
    c = C()
    c.__len__() = lambda: 5
    len(c)
    # `rasie TypeError`
    • 元属性定义在实例字典中会引发异常
    • 若元属性的隐式查找过程使用了传统查找过程,会在对类型 对象本身发起调用时失败
    • 可以通过在查找元属性时绕过实例避免

      1
      2
      >>> type(1).__hash__(1) == hash(1)
      >>> type(int).__hash__(int) == hash(int)

上下文管理器协议

上下文管理器:定义了在执行with语句时要建立的运行时上下文 的对象

  • 上下文管理器为执行代码块,处理进入、退出运行时所需上下文

    • 通常使用with语句调用
    • 也可以直接调用协议中方法方法
  • 典型用法

    • 保存、恢复各种全局状态
    • 锁、解锁资源:避免死锁
    • 关闭打开的文件:自动控制资源释放
  • 可利用contextlib模块方便实现上下文管理器协议

__enter__

1
2
def contextmanager.__enter__(self):
pass
  • 用途:创建、进入与当前对象相关的运行时上下文

    • 在执行with语句块前设置运行时上下文
  • 返回值

    • with子句绑定方法返回值到as子句中指定的目标,如果 方法返回值

__exit__

1
2
def contextmanger.__exit__(self, exc_type, exc_value, traceback):
pass
  • 用途:销毁、退出关联到此对象的运行时上下文

    • with语句块结束后,__exit__方法触发进行清理工作
    • 不论with代码块中发生什么,即使是出现异常, __exit__控制流也会执行完
  • 参数:描述了导致上下文退出的异常,正常退出则各参数为 None

    • exc_type
    • exc_value
    • traceback
  • 返回值:布尔值

    • 若上下文因异常退出
      • 希望方法屏蔽此异常(避免传播),应该返回真值, 异常被清空
      • 否则异常在退出此方法时将按照正常流程处理
    • 方法中不应该重新引发被传入的异常,这是调用者的责任

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from socket import socket, AF_INET, SOCK_STREAM

class LazyConnection:
def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
self.address = address
self.family = family
self.type = type
self.connections = []

def __enter__(self):
sock = socket(self.family, self.type)
sock.connect(self.address)
self.connections.append(sock)
return self.sock

def __exit__(self, exc_ty, exc_val, tb):
self.connections.pop().close()

from functools import partial

def test():
conn = LazyConnection("www.python.org", 80))
with conn as s1:
# `conn.__enter___()` executes: connection opened
s.send(b"GET /index.html HTTP/1.0\r\n")
s.send(b"Host: www.python.org\r\n")
s.send(b"\r\n")
resp = b"".join(iter(partial(s.recv, 8192), b""))
# `conn.__exit__()` executes: connection closed

with conn as s2:
# 此版本`LasyConnection`可以看作是连接工厂
# 使用列表构造栈管理连接,允许嵌套使用
pass

迭代器协议

  • 可迭代对象:实现__iter__方法的对象
  • 迭代器对象:同时实现__next__方法的可迭代对象
  • 使用collections.abc模块判断对象类型

__iter__

1
2
def object.__iter__(self):
pass
  • 用途:创建迭代器对象,不负责产生、返回迭代器元素

    • 容器对象要提供迭代须实现此方法
      • 容器支持不同迭代类型,可以提供额外方法专门请求 不同迭代类型迭代器
    • 迭代对象本身需要实现此方法,返回对象自身
      • 允许容器、迭代器均可配合for...in...语句使用
  • 返回值:迭代器对象

    • 映射类型应该逐个迭代容器中键
    • 内置钩子函数:iter()
  • 此方法对应Python/C API中python对象类型结构体中 tp_iter槽位

__next__

1
2
def object.__next__():
pass
  • 用途:从迭代器中返回下一项

    • 若没有项可以返回,则raise StopIteration
    • 一旦引发raise StopIteration,对后续调用必须一直 引发同样的异常,否则此行为特性无法正常使用
  • 返回值:迭代器对象中下个元素

    • 映射类型返回容器中键
    • 内置钩子函数:next()
  • 此方法对应Python/C API中python对象类型结构体中 tp_iternext槽位

协程/异步

__await__

1
2
def object.__await__(self):
pass
  • 用途:用于实现可等待对象

  • 返回值:迭代器

    • 钩子运算:await
  • asyncio.Future实现此方法以与await表达式兼容

Awaitable Objects

可等待对象:异步调用句柄,等待结果应为迭代器

  • 主要是实现__await__方法对象

    • async def函数返回的协程对象
  • type.coroutine()asyncio.coroutine()装饰的生成器 返回的生成器迭代器对象也属于可等待对象,但其未实现 __await__

  • 协程对象参见cs_python/py3ref/dm_gfuncs
  • py3.7前多次await可等待对象返回None,之后报错

异步迭代器协议

  • 异步迭代器常用于async for语句中
  • 其他参见迭代器协议

__aiter__

1
2
def object.__aiter__(self):
pass
  • 用途:返回异步迭代器对象,不负责产生、返回迭代器元素
    • 返回其他任何对象都将raise TypeError
  • 其他参见__iter__方法

__anext__

1
2
async def object.__anext__(self):
pass
  • 返回:从异步迭代器返回下个结果值

    • 迭代结束时应该raise StopAsyncIteration
  • 用途

    • 在其中调用异步代码
  • 其他参见__next__方法

1
2
3
4
5
6
7
8
9
10
class Reader:
async def readline(self):
pass
def __aiter__(self):
return self
async def __anext__(self):
val = await self.readline()
if val == "b":
raise StopAsyncIteration
return val

异步上下文管理器协议

  • 异步上下文管理器常用于async with异步语句中
  • 其他参见上下文管理器协议

__aenter__

1
2
async def object.__aenter__(self):
pass
  • 用途:异步创建、进入关联当前对象的上下文执行环境

    • async def定义为协程函数,即在创建上下文执行环境 时可以被挂起
  • 返回:可等待对象

  • 其他参见__enter__

__aexit__

1
2
async def object.__aexit__(self):
pass
  • 用途:异步销毁、退出关联当前对象的上下文执行环境

    • async def定义为协程函数,即在销毁上下文执行环境 时可以被挂起
  • 返回:可等待对象

  • 其他参见__exit__函数