pythonAPI:https://docs.python.org/zh-cn/3/library/index.html
教程cookbook:https://python3-cookbook.readthedocs.io/zh_CN/latest/preface.html
基础
浮点数精度
https://blog.csdn.net/qq_51432387/article/details/122624679
https://blog.csdn.net/qq_32727095/article/details/118106061
简而言之 最好别用浮点数来比较大小
Python 3.X对于浮点数默认的是提供17位数字的精度。
#使用模块前,需要使用 import 引入
import decimal
a = decimal.Decimal("10.0")
b = decimal.Decimal("3")
print(10.0/3)
print(a/b)
#输出:3.3333333333333335
#输出:3.333333333333333333333333333
# python保留小数点后几位
# 1.%f方法 不过最终是字符串
ans.append("$%.2f" % (quantity * (100 - discount) / 100))
f = 1.23456
print('%.4f' % f)
# 只不过是字符串,需要再用float转换
# 2.format函数 会四舍五入
print(format(1.23456, '.2f'))
print(format(1.23456, '.3f'))
print(format(1.23456, '.4f'))
#1.23
#1.235
#1.2346
# 3.不进行四舍五入 直接截短
#保留三位小数截断 python3
print(int(1.23456 * 1000) / 1000 )
输入输出
print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 **end=””**:
True和False可以直接当成0和1来用
>>> True == 1
True
>>> False == 0
True
>>> True + False + 20
21
//:整数除法
\:可以使用这个换行,运算符后边不会错
格式化输出,文字和数字等混合输出时使用!
# 第一种:使用format
"Skipping {}".format(img_path)
# 不设置指定位置,按默认顺序
>>>"{} {}".format("hello", "world")
'hello world'
# 设置指定位置
>>> "{1} {0} {1}".format("hello", "world")
'world hello world'
# 设置参数
print("网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com"))
# 通过字典设置参数
site = {"name": "菜鸟教程", "url": "www.runoob.com"}
print("网站名:{name}, 地址 {url}".format(**site))
# 通过列表索引设置参数
my_list = ['菜鸟教程', 'www.runoob.com']
print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的
数字格式化:

^, <, >
分别是居中、左对齐、右对齐,后面带宽度
:
号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。
+
表示在正数前显示 +
,负数前显示 -
(空格)表示在正数前加空格
b、d、o、x
分别是二进制、十进制、八进制、十六进制。
#第二种
print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
#%5d %5s输出站5个字符宽度,不足补足 %.3f表示保留三位小数
#第三种
f'asdf {变量名}'
终端输出带颜色的文本
这在某种程度上取决于您所使用的平台。 最常见的方法是打印ANSI转义序列。 举一个简单的例子,这是来自的一些Python代码:
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
# 为了使用这样的代码,你可以这么做:
print(bcolors.WARNING + "Warning: No active frommets remain. Continue?" + bcolors.ENDC)
# 或者
print(f"{bcolors.WARNING}Warning: No active frommets remain. Continue?{bcolors.ENDC}")
输入
# Python3.x 中 input() 函数接受一个标准输入数据,返回为 string 类型。
input([prompt])
>>>a = input("input:")
input:123 # 输入整数
>>> type(a)
<class 'str'> # 字符串
>>> a = input("input:")
input:runoob # 正确,字符串表达式
>>> type(a)
<class 'str'> # 字符串
文件
文件读取输出
with open("locs.txt","a") as f:
#f.write(fname+"\n")
for line in f.readlines(): #每个line都是str
linelist=line.split()#字符串切割
#with open as f: 为了保证无论是否出错都能正确地关闭文件
#文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的
#由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。
#所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来实现
try:
f = open('/path/to/file', 'r')
print(f.read())
finally:
if f:
f.close()
#但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法
files = file.read().splitlines()
#splitlines() 按照行界符('\r', '\r\n', \n'等)分隔,返回一个包含各行作为元素的列表,默认不包含行界符。
file.read()
#一次读取文件的全部内容,把内容读到内存,用一个str对象表示,file.read(size)表示最多读size个字节
file.readline()
#每次读取一行;返回的是一个字符串对象,保持当前行的内存
file.readlines():
#读取所有行然后把它们作为一个字符串列表返回。
with open('mytest.txt','w',encoding='utf-8') as f:#w是覆盖,a是追加
for i in range(len(a)):
f.write(a[i]+'\n')
一个stackoverflow问题
for line in open(filename):
do_something(line)
#为什么经常看到这种写法?为什么不是下面这种
with open(filename) as f:
for line in f.readlines():
do_something(line)
#1:with更好
#2:for line in f足够,for line in f.readlines()反而冗余,我推测是f所属的类实现了相应__iter__()方法
#3:在简短的脚本中,人们经常省略这一步,因为在垃圾回收过程中,当文件对象被回收时,Python会自动关闭文件。然而,尽快关闭文件是一种良好的编程实践,在大型程序中尤其如此。
绝对路径和相对路径
- u:后面字符串以Unicode格式进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时出现乱码。
- r:raw,去掉反斜杠的转移机制。
- b:后面字符串是bytes 类型。
- f:以f开头表示在字符串内支持大括号内的python 表达式。
函数
str.split(str="", num=string.count(str))#返回分割后的字符串列表。
#str,分割符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
#num,分割次数。默认为 -1, 即分割所有。
#split(",")按逗号分割,最后一条是带换行符的!
# 统计字符串里某个字符或子字符串出现的次数。可选参数为在字符串搜索的开始与结束位置。
str.count(sub, start= 0,end=len(string))
strip()# 处理的时候,如果不带参数,默认是清除两边的空白符,例如:\n,\r,\t,' '。
str = '123@163.com'
print(str.strip('132'))
#@163.com
str = '123@163.com'
print(str.strip('23'))
#123@163.com
S.rstrip([chars])
#用于删除字符串尾部指定的字符,默认字符为所有空字符,包括空格、换行(\n)、制表符(\t)等
startwith()#是否以指定字符串开头
str.endswith(suffix[, start[, end]])# 是否以指定字符串结尾
str.endswith(suffix, 2, 6);
str = "hello,i love python"
print("1:",str.startswith("h"))
print("2:",str.startswith("l",2,10))#beg=2,end=10
print("3:",str.startswith("")) #空字符
1: True
2: True
3: True
'sep'.join(元组、列表、字典、字符串)->str
#返回一个以分隔符sep连接各个元素后生成的字符串,字典只对键进行连接
replace
#字符串运算遵循数学法则,单引号和双引号可以混合使用
>>>3*"python"+'1'
#pythonpythonpython1
#多个带引号的字符串,解释器会自动拼接
>>>print('a''b')#ab
# 判断是否为数字
print(str_1.isdigit())
# 判断是否为字母
print(str_1.isalpha())
# 判断是否为字母数组混合
print(str_1.isalnum())
# 把所有字符中的小写字母转换成大写字母
print(str.upper())
# 把所有字符中的大写字母转换成小写字母
print(str.lower())
# 把第一个字母转化为大写字母,其余小写
print(str.capitalize())
# 字符串中查找指定字符位置
str.find(str, beg=0, end=len(string))
>>>info = 'abca'
>>> print info.find('a') # 从下标0开始,查找在字符串里第一个出现的子串,返回结果:0
>>> print info.find('a',1) # 从下标1开始,查找在字符串里第一个出现的子串:返回结果3
>>> print info.find('3') # 查找不到返回-1
# 从后往前查找
str.rfind()
# 腾讯笔试给我做麻了,字符串in的用法
"A" in "AC" # True
"C" in "AC" # True
"AC" in "ACD" # True
"CD" in "ACD" # True
"AD" in "ACD" #False
变量赋值规则
在python中使用id(obj)
函数查看变量的地址
a=10
,并不是为标记a建立一个值,而是建立了一个值以后,再用标记a去指向它a=10 b=a a=20
,b=a不是b指向了标记a,而是b指向了标记a指向的值,所以a指向20之后,b还是10g= 10 a= g a=a+4
,a会指向一个新的内存n=['a','b','c'] n[0]=['x','y']
,改变的是所指向的对象的本身,内部没有改变
nums[nums[i]], nums[i] = nums[i], nums[nums[i]]
实际的执行是t=(nums[i], nums[nums[i]]),nums[nums[i]]=t[0],nums[i]=t[1]
,顺序上是有先后的
for i in range(5):
for j in range(5):
# 如果在循环里将i,j修改了,就会在新的i,j的值上加一继续循环
基本数据结构


列表list/序列
# 返回一个新的列表,b和a不共享
# a=list("a,b,c,d,e,!")=>a=['a','b','c','d','e']
list() eg:b=list(a)
# 向列表添加元素
list.append()
# 从列表中找出某个值第一个匹配项的索引位置
list.index(obj)
# extend() 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.extend(seq)
# 将对象插入列表
# 这个extend很多时候还容易出错,完全用处不太大
# 两个列表直接 list1+list2就行
# 只不过extend是原地修改,list1+list2是返回一个新的列表
list.insert(index, obj)
# 列表乘法
[0]*5#是地址复制五遍 常数可以 [0,0,0,0,0]
[a]*5#这5个元素地址相同,改一个全都改了
索引与切片
# 左闭右开
a[2:6]
# 从第2个开始到后面所有的元素
a[2:]
# 从a[m]开始,每次走|n|步,当n为负时逆序取数,当n为正的时候,m为空则默认m=0,n为负时,m为空则默认为-1
a[m::n]
# 切片中的None用来升维
a = torch.eye(6)
print(a.shape) # torch.Size([6, 6])
b=a[None,:,:]
print(b.shape) # torch.Size([1, 6, 6])
b = a[i:j] # 表示复制a[i]到a[j-1],以生成新的list对象
a = [0,1,2,3,4,5,6,7,8,9]
b = a[1:3] # [1,2]
#当越界时
b = a[7:45] #[7,8,9],自动截取到末尾
# 当i缺省时,默认为0,即 a[:3]相当于 a[0:3]
# 当j缺省时,默认为len(alist), 即a[1:]相当于a[1:10]
# 当i,j都缺省时,a[:]就相当于完整复制一份a
b = a[i:j:s] # 表示:i,j与上面的一样,但s表示步进,缺省为1.
# 所以a[i:j:1]相当于a[i:j]
# 当s<0时,i缺省时,默认为-1. j缺省时,默认为-len(a)-1
# 所以a[::-1]相当于 a[-1:-len(a)-1:-1],也就是从最后一个元素到第一个元素复制一遍,即倒序。

集合推导式和字典推导式与列表推导式类似,只不过把中括号[]**换成了大括号{}**
生成器推导式是将中括号[]**换为圆括号()**
# 实现切片
class slice(stop)
class slice(start, stop[, step])
# start:开始位置 stop:结束为止 step:间隔
>>>myslice = slice(5) # 设置截取5个元素的切片
>>> myslice
slice(None, 5, None)
>>> arr = range(10)
>>> arr
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> arr[myslice] # 截取 5 个元素
[0, 1, 2, 3, 4]
字典dict/集合set
# 给字典添加新元素
a["new_key"] = new_value
a=b.pop("value")
#删除字典中给定键key所对应的值,返回值为被删除的值。
a=b.keys()#或b.values()或b.items()
#返回值都是view objects,它们提供了关于字典条目的动态视图,这意味着当字典发生变化时,视图会反映这些变化。
#支持len(dictview)、iter(dictview)、x in dictview
#若想支持map-style,可以a=list(b.keys())转化成列表
car = {"brand": "Porsche", "model": "911", "year": 1963}
car.update({"year": "White"})
print(car)
{'brand': 'Porsche', 'model': '911', 'year': 'White'}
# 向字典插入项目,如项目已存在,则更新该项目
dic.get(key,default)
# 返回指定键的值,如果键不在字典中返回默认值None或者设置的默认值。
discard(self, *args, **kwargs)
# 如果在set集合中存在元素x, 则删除
remove(self, *args, **kwargs)
# 从set集合中删除元素,如果不存在则引发 KeyError
pop(self, *args, **kwargs)
# 删除并且返回set集合中的一个不确定的元素,如果为空则引发KeyError
for i in dic:#这样就是只遍历key值,没有value
# 集合的交集 并集 差集
set1 ={'卢俊义','花荣', '吴用'}
set2 ={'公孙胜','秦明','卢俊义'}
res = set1 & set2#{'卢俊义'} 交
res = set1 - set2 # 差
res = set1 | set2 # 并
set1.add("宋江")# 增
res = set1.remove("吴用")# 删
#列表转set
a=[1,2,2]
b=set(a)#{1,2}
函数
# zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
# 拆包
zip(*zipped)
[(1, 2, 3), (4, 5, 6)]
# 返回一个整数 int 或者长整数 long int 的二进制表示。
>>>bin(10)
'0b1010'
>>>bin(10)[2:]
'1010'
# Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。
>>>(bin(10)[2:].zfill(6))
'0'
# ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数
# 返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。
>>>ord('a')
# 97
# eval()用来执行一个字符串表达式,并返回表达式的值。
>>>x = 7
>>> eval( '3 * x' )
21
# python分号 如果要在⼀⾏中书写多条句,就必须使⽤分号分隔每个语句,否则Python⽆法识别语句之间的间隔:
# 使⽤分号分隔语句
x=1; y=1 ; z=1
# any(x)判断x对象是否为空对象,如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true。
any()
>>> any([0,'0',''])
True
>>> any([0,''])
False
# all(x)如果all(x)参数x对象的所有元素不为0、’’、False或者x为空对象,则返回True,否则返回False。
all()
>>> all(('a', 'b', 'c', 'd')) #元组tuple,元素都不为空或0
True
>>> all(('a', 'b', '', 'd')) #元组tuple,存在一个为空的元素
False
# 两列表元素对应相乘
map(lambda (a,b):a*b,zip(List1,List2))
# 使用python不用numpy自己实现逆矩阵
# https://integratedmlai.com/matrixinverse/
AM = I
n =len(AM)
IM = getI(n)
indices = list(range(n))
for fd in range(0,n):
fdScaler = F(1,AM[fd][fd])
for j in range(n):
AM[fd][j] *= fdScaler
IM[fd][j] *= fdScaler
for i in indices[:fd] + indices[fd+1:]:
crScaler = AM[i][fd]
for j in range(n):
AM[i][j] = AM[i][j] - crScaler * AM[fd][j]
IM[i][j] = IM[i][j] - crScaler * IM[fd][j]
return IM
# map竟然是内置函数
# 返回一个将 function 应用于 iterable 中每一项并输出其结果的迭代器。
# 如果传入了额外的 iterable 参数,function 必须接受相同个数的实参并被应用于从所有可迭代对象中并行获取的项。
# 当有多个可迭代对象时,最短的可迭代对象耗尽则整个迭代就将结束。
map(function, iterable, ...)
#filter()函数用于过滤序列,过滤掉不符合条件的元素,返回符合条件的元素组成新列表。
filter(function,iterable)#function:判断函数 iterable:可迭代对象
# 在十万级别数据上,filter的速度大约是for循环的1000倍。
enumerate()
enumerate() 函数用于将**一个可遍历的数据对象(如列表、元组或字符串)**组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 小标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
排序函数
#应用在list上的方法,对已经存在的列表进行操作,是inplace的无返回值
list.sort(*, key=None, reverse=False)# 默认从小到大
# 如果reverse设置为True就从大到小
# 可以使用 functools.cmp_to_key() 将 2.x 风格的 cmp 函数转换为 key 函数。好像python3不支持比较函数
# functools.cmp_to_key() <则返回负数,如-1 >则返回整数,如1 =则返回0
sorted(iterable, cmp=None, key=None, reverse=False)
#内置函数,可以对所有可迭代的对象进行排序操作,返回副本,原始输入不变。
# 集合是对可迭代对象的一个统称,他们可以是列表、字典、set、甚至是字符串),它的功能非常强大
#iterable:可迭代对象
#cmp:比较函数,具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
#key:指定可迭代对象中的一个元素来进行排序。
#reverse:排序规则,True为降序,False为升序
>>> L=[('b',2),('a',1),('c',3),('d',4)]
>>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利用cmp函数
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> sorted(L, key=lambda x:x[1]) # 利用key
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# sorted 也可以根据多个字段来排序
class tuple_list:
def __init__(self, one, two, three):
self.one = one
self.two = two
self.three = three
def __repr__(self):
return repr((self.one, self.two, self.three))
tuple_list_ = [tuple_list('C', 1,5), tuple_list('A', 3,2), tuple_list('C', 2,6)]
# 首先根据one的位置来排序,然后根据two的位置来排序
sorted(tuple_list_, key=lambda x:(x.one, x.two))
Out[112]: [('A', 3, 2), ('C', 1, 5), ('C', 2, 6)]
# sorted对字典进行排序
dic = {'chen': 24, 'alex': 34, 'egon': 37, 'evaJ':'18'}
s_dic = sorted(dic.keys()) # 只对key排序,结果也只有key
print(s_dic)
s_dic1 = sorted(dic.items(), key=lambda x: x[0]) # 结果包含key,和value
print(s_dic1)
# 输出结果
# ['alex', 'chen', 'egon', 'evaJ']
# [('alex', 34), ('chen', 24), ('egon', 37), ('evaJ', '18')]
a = [(5,3),(4,2)]
b = sorted(a)#这种有两个元素的,如果没有指定key,默认是按照第一个元素当做key
自定义排序(招商银行某道题)
def compare1(elem):
if isinstance(elem, int):
return elem
elif isinstance(elem, str):
return -1
else:
return -1
def compare2(elem):
if elem == '?':
return chr(127)
else:
return elem
student = sorted(student, key=lambda w: (-compare1(w[4]), compare2(w[0])))
匿名函数
用lambda函数首先减少了代码的冗余,其次,用lambda函数,不用费神地去命名一个函数的名字,可以快速的实现某项功能,最后,lambda函数使代码的可读性更强,程序看起来更加简洁。
lambda 参数列表:表达式
表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的
c=lambda x,y,z:x*y*z
c(2,3,4) #24
函数属性
def get_fun_name(func):
return func.__name__#返回的就是函数的名字
def say_hello():
pass
def main():
# 看起来没有用处呀
print(get_fun_name(say_hello))
# 那么看下面
haha = say_hello
hahaha = haha
# 请问 hahaha 到底是啥?
print(get_fun_name(hahaha))
#函数名字是最开始的那个实例,其他都是函数的引用。
if __name__ == '__main__':
main()
say_hello
say_hello
and和or
# and的返回结果问题:
# 从左到右计算表达式,若所有的都为真,则返回最后一个值,若存在假,返回第一个假值.
>>> 0 and False and 1
0
>>> 1 and False and 5
False
>>> 1 and 3 and False and 5
False
>>> 1 and 2 and 0 and False and 5
0
# or的返回结果问题:
# 从左到右计算表达式,只要遇到真值就返回那个真值,如果表达式结束依旧没有遇到真值,就返回最后一个假值.
>>> 1 or 2 or False
1
>>> False or 2 or False
2
>>> False or 1 and 2
2
稍微不那么基础的
类
基本知识
dir()
和__dict__
eg:dir(nn.Module)
dir函数可以返回参数的属性、方法的列表
__init__()
和__new__()
造方法包括创建对象和初始化对象,在python当中,分为两步执行:先执行__new__
方法,然后执行__init__
方法;
__init__
是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
__new__
是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
也就是,__new__
在__init__
之前被调用,__new__
的返回值(实例)将传递给__init__
方法的第一个参数,然后__init__
给这个实例设置一些参数。__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以return父类__new__
出来的实例,或者直接是object的__new__
出来的实例
__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值
我们可以将类比作制造商,__new__
方法就是前期的原材料购买环节,__init__
方法就是在有原材料的基础上,加工,初始化商品环节
__call__()
为了将类的实例对象变为可调用对象,相当于重载()
运算符
Python中的函数是一级对象。这意味着Python中的函数的引用可以作为输入传递到其他的函数/方法中,并在其中被执行。
而Python中类的实例(对象)可以被当做函数对待。也就是说,我们可以将它们作为输入传递到其他的函数/方法中并调用他们,正如我们调用一个正常的函数那样。而类中__call__()
函数的意义正在于此。为了将一个类实例当做函数调用,我们需要在类中实现__call__()
方法。也就是我们要在类中实现如下方法:def __call__(self, *args)
。这个方法接受一定数量的变量作为输入。
假设x是X类的一个实例。那么调用x.__call__(1,2)
等同于调用x(1,2)
。这个实例本身在这里相当于一个函数。
class X(object):
def __init__(self, a, b, range):
self.a = a
self.b = b
self.range = range
def __call__(self, a, b):
self.a = a
self.b = b
print('__call__ with ({}, {})'.format(self.a, self.b))
def __del__(self, a, b, range):
del self.a
del self.b
del self.range
>>> xInstance = X(1, 2, 3)
>>> xInstance(1,2)
__call__ with (1, 2)
__len__()
def __len__(self):
return len(self.ids)
#对于一个list,可以直接使用len([1,2,3])
#而对于一个对象,里面有很多东西,没法直接使用len,所以要写内置函数__len__(),以后就可以len(对象)
__getitem__()
如果在类中定义了__getitem__()
方法,那么他的实例对象(假设为P)就可以这样P[key]取值。当实例对象做P[key]运算时,就会调用类中的__getitem__()
方法。
此外,在用 for..in..
迭代对象时,如果对象没有实现 __iter__
__next__
迭代器协议,Python的解释器就会去寻找__getitem__
来迭代对象,如果连__getitem__
都没有定义,这解释器就会报对象不是迭代器的错
__qualname__
__qualname
相比__name__
给予更多的信息,因此在debugging的时候可以给予更多的帮助,例如:
>>> def f(): pass
... class A:
... def f(self): pass
... class A:
... def f(self): pass
...
>>> # __name__ is not showing the path, so these functions look equal
>>> f.__name__
'f'
>>> A.f.__name__
'f'
>>> A.A.f.__name__
'f'
>>> # And these classes looks equal
>>> A.__name__
'A'
>>> A.A.__name__
'A'
>>>
>>> # __qualname__ shows the path, so these functions are distinguishable
>>> f.__qualname__
'f'
>>> A.f.__qualname__
'A.f'
>>> A.A.f.__qualname__
'A.A.f'
>>> # And these classes are distinguishable
>>> A.__qualname__
'A'
>>> A.A.__qualname__
'A.A'
__slots__
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法。但是,如果我们想要限制实例的属性怎么办?为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性:
>>> class Student:
... __slots__ = ('name', 'age')
...
>>> s = Student()
>>> s.name = 'digg'
>>> s.age = '19'
>>> s.score = 99
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
使用__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
__slots__
存在的真正原因是用于优化,否则我们是以__dict__
来存储实例属性,如果我们涉及到很多需要处理的数据,使用元组来存储当然会节省时间和内存。如果我们还是想要有可以随意添加实例属性,那么把__dict__
放入__slots__
中既可,实例会在元组中保存各个实例的属性,此外还支持动态创建属性,这些属性存储在常规的__dict__
中。优化完全就不见了。o(╯□╰)o
>>> class Student:
__slots__ = ('name', 'age', '__dict__')
>>> s.score = 99
>>> s.score
99
对于具有已知属性的小类,它可能是一个瓶颈。浪费了dict
很多内存。Python 不能只在创建对象时分配静态内存量来存储所有属性。因此,如果您创建大量对象(我说的是成千上万),它会占用大量 RAM。仍然有一种方法可以规避这个问题。它涉及使用__slots__
来告诉 Python 不要使用 dict,并且只为一组固定的属性分配空间。
@staticmethod
静态方法和@classmethod
类方法
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
def foo(x):
print "executing foo(%s)"%(x)
class A(object):
def foo(self, x):#self是对实例的绑定,a.foo(x)其实是foo(a,x),对象实例a隐式地作为第一个参数传递
print "executing foo(%s, %s)" % (self, x)
@classmethod
def class_foo(cls, x):#cls是对类的绑定,和self类似
print "executing class_foo(%s, %s)" % (cls, x)
@staticmethod
def static_foo(x):#self(对象实例)和 cls(类)都不会隐式传递为第一个参数。它们的行为类似于普通函数
print "executing static_foo(%s)" % x
a = A()
私有属性和方法
仅开头带双下划线__的命名,用于对象的数据封装,以此命名的属性或者方法为类的私有属性或者私有方法,eg:
def __spam(self):
这就起到了隐藏数据的作用,但是这种实现机制并不是很严格,机制是通过自动”变形”实现的,类中所有以双下划线开头的名称__name都会自动变为_类名__name
的新名称。另外这种机制可以阻止继承类重新定义或者更改方法的实现。
在类中也可以用单下划线开头来命名属性或者方法,这只是表示类的定义者希望这些属性或者方法是”私有的”**,但实际上并不会起任何作用。**
装饰器和@符号
python中的函数可以像普通变量一样当做参数传递给另外一个函数
def foo():
print("foo")
def bar(func):
func()
bar(foo)
具体看这一篇:https://gohom.win/2015/10/25/pyDecorator/
这一篇讲的更清楚https://foofish.net/python-decorator.html
简单来说就是复合函数,概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能
def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
@log
def now():
print '2015-10-26'
return "done"
now()
#添加了装饰器之后,现在运行now(),等于运行log(now)把now传递进去了
内置的@property和@*.setter,其实认真看完实例就明白了,就相当于python的get和set方法,关于这两个内置装饰器可以看这个:@property和@xxx.setter
看这段代码:
import tensorflow as tf
class D(object):
def __init__(self, dataset_dir: str, batch_size: int,train_dataset=None):
self.dataset_dir = dataset_dir
self.batch_size = batch_size
self.val_dataset = None
self.train_dataset = train_dataset#这里调用的set方法
self.test_dataset = None
#train_dataset get set 方法
@property
def train_dataset(self):
return print(self.__train_dataset)
@train_dataset.setter
def train_dataset(self, dataset):
self.__train_dataset = dataset #这里新定义了一个属性
print("!!!!")
d=D("asdf",5,2)
d.train_dataset
#!!!!
#2
继承
class UNet(nn.Module):#继承了nn.Module
def __init__(self, n_channels, n_classes, bilinear=True):#子类的__init__函数
super(UNet, self).__init__()
#把父类全部继承,你有想改的,你再自己改!你重写了父类的方法,还想用父类的方法,怎么办?利用super()函数 eg:super().fun()
#如果自己也定义了__ __init____ 方法,那么父类的属性是不能直接调用的
#可以在 子类的 __init__中调用一下父类的 __init__ 方法,这样就可以调用
python中父类可以调用子类的属性和方法,我怀疑是子类super.__init__()
时把子类的self传过去了,父类本身找不到,就找子类的。
class Animal:
def a1(self):
print("调用a1")
self.eat()#这一步会调用子类的方法
def eat(self):
print('kkkkkk')
class Person(Animal):
def p1(self):
print("调用p1")
self.a1()
def eat(self):
print('hhhhhhhh')
p = Person()
p.p1()#父类也实现了,子类也实现了,会优先使用子类重写的方法
#调用p1
#调用a1
#hhhhhhhh
关键字
python官网文档对于super的介绍来看,其作用为返回一个代理对象作为代表调用父类或亲类方法。(Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. )
super()的主要用法有两种: 在单类继承中,其意义就是不需要父类的名称来调用父类的函数,因此当子类改为继承其他父类的时候,不需要对子类内部的父类调用函数做任何修改就能调用新父类的方法。 比如:
#!/usr/bin/env python2.7
class base1(object): # class base2(object):
def __init__(self): # def __init__(self):
print "base1 class" # print "base2 class"
# 若继承父类需要换成base2
class A(base1): # class A(base2):
def __init__(self): # def __init__(self):
base1.__init__(self) # base2.__init__(self)
class B(base1): # class B(base2):
def __init__(self): # def __init__(self):
super(B, self).__init__() # super(B, self).__init__()
super(Class,self)
#在python2 super把子类的类名和self示例传给父类
super()
#python3变成了隐式的了
class A:
def __init__(self):
self.n = 2
def add(self, m):#执行时执行的是super传递过来的self,是子类的实例而不是父类的实例
print('self is {0} @A.add'.format(self))
self.n += m
class B(A):
def __init__(self):
self.n = 3
def add(self, m):
print('self is {0} @B.add'.format(self))
super().add(m)
self.n += 3
b = B()
b.add(2)
print(b.n)#输出
#self is <__main__.B object at 0x106c49b38> @B.add
#self is <__main__.B object at 0x106c49b38> @A.add
#8
关于cls
也是类似的
class A:
def __new__(cls):
super(A, cls).__new__(cls)
class B(A):
def __new__(cls):
super(B, cls).__new__(cls)
B()
would trigger B.__new__(B)
which would trigger A.__new__(B)
, which would trigger object.__new__(B)
, so you’d end up with an instance of B
global
如果局部要对全局变量修改,应在局部声明该全局变量。
# 一旦在函数内给变量赋值,就定义了一个局部变量。但如果确实需要在函数内去修改全局变量的值,而不是定义局部变量,
# 使用global关键词声明这个变量就是外面的全局变量;
# global关键字
name = '张三'
def change_name():
global name
name = 'lisi'
print('函数内改成',name)
print('全局变量',name)
change_name()
print('全局变量',name)
nonlocal
nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
def nonlocal_test():
count = 0
def test2():
nonlocal count
count += 1
return count
return test2
val = nonlocal_test()
print(val())# 1
print(val())#
print(val())
not和is
# None, False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()都相当于False,但是不包括自定义类
# not None == not False == not '' == not 0 == not [] == not {} == not ()
>>> x = []
>>> y = None
>>>
>>> x is None
False
>>> y is None
True
>>>
>>>
>>> not x
True
>>> not y
True
# 结论: `if x is not None`是最好的写法,清晰,不会出现错误,以后坚持使用这种写法。
# 如果比较相同的对象实例,is总是返回True 而 == 最终取决于 "eq()"
>>> class foo(object):
def __eq__(self, other):
return True
>>> f = foo()
>>> f == None
True
>>> f is None
False
>>> list1 = [1, 2, 3]
>>> list2 = [1, 2, 3]
>>> list1==list2
True
>>> list1 is list2
False
# (ob1 is ob2) 等价于 (id(ob1) == id(ob2))
函数
hasattr(object,name)
#object:对象 name:字符串,属性名
#如果对象有该属性返回true,否则返回false
getattr(object, name[, default])
#用于返回一个对象属性值
>>>class A(object):
bar = 1
>>> a = A()
>>> getattr(a, 'bar') # 获取属性 bar 值
>>> 1
setattr(object, name, value)
# 对应函数 getattr(),用于设置属性值,该属性不一定是存在的。
>>>class A(object):
... bar = 1
...
>>> a = A()
>>> getattr(a, 'bar') # 获取属性 bar 值
1
>>> setattr(a, 'bar', 5) # 设置属性 bar 值
>>> a.bar
vars([object])
#带参数:返回对象object的属性和属性值的字典对象,或者说返回对象的__dict__属性
#不带参数:作用同locals(),即以字典对象返回当前位置的全部局部变量
>>> print(vars(Runoob))
{'a': 1, '__module__': '__main__', '__doc__': None}
参数和返回值
return self
其实就是返回自身实例,用于链式调用 看这篇教程
多个返回值或返回字典
多个返回值,返回的是一个tuple
# __slots__是一个元组
__slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
# 返回的是一个字典
return {
'image': torch.from_numpy(img).type(torch.FloatTensor),
'mask': torch.from_numpy(mask).type(torch.FloatTensor)
}
可变长度参数与可迭代对象参数
*args
将参数打包成tuple给函数体调用
**kwargs
打包关键字参数成dict给函数体调用
注意点:参数arg
、*args
、**kwargs
三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)
这个顺序,否则程序会报错。
def function(arg,*args,**kwargs):
print(arg,args,kwargs)
function(6,7,8,9,a=1, b=2, c=3)#注意传参方式!
#6 (7,8,9) {'c':3,'a':1,'b':2}
data_kwargs = {'transform': 1, 'base_size': 2,
'crop_size': 3, 'logger': 4,
'scale': 5}
def get_segmentation_dataset(name, **kwargs):
print(kwargs)
get_segmentation_dataset("1", split=1, a=2, **data_kwargs)
#**data_kwargs先解包,然后再和split=1, a=2 一起传入为字典
#注意,元组整体传参前面必须加*,字典前面必须加**
#列表前面加星号作用是将列表中所有元素解开成独立的参数,传入函数,参数数量等于len(data)
>>>print(*[1, 2, 3])
1 2 3
类型注解
def add_to_graph(self, dataset) -> tf.data.Dataset:
箭头的作用是给函数添加注解,用来说明返回值的数据类型
def get_filters_count(level: int, initial_filters: int) -> int:
冒号的作用是说参数的数据类型
在实际使用中, Any, Union, Tuple, List, Sequence, Mapping, Callable, TypeVar,Optional, Generic
等的使用频率比较高,其中Union、Optional、Sequence、Mapping
非常有用,注意掌握。
Union
即并集,所以Union[X, Y]
意思是要么X类型、要么Y类型
Optional
Optional[X]
与Union[X, None]
,即它默认允许None类型
Sequence
即序列,需要注意的是,List
一般用来标注返回值;Sequence、Iterable
用来标注参数类型
Mapping
即字典,需要注意的是,Dict
一般用来标注返回值;Mapping
用来标注参数类型
Any
Any与任何类型兼容
类型检查函数
isinstance(object,classinfo)
判断一个变量object是否是classinfo类型的。与type区别:type不会考虑子类是一种父类类型,不考虑继承关系;instance认为是,考虑继承关系。
异常处理
python解释器检测到错误,触发异常(也允许程序员自己触发异常)。程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)。如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理。
程序运行中的异常可以分为两类:语法错误和逻辑错误。首先,我们必须知道,语法错误跟异常处理无关,所以我们在处理异常之前,必须避免语法上的错误。
#AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
#IOError 输入/输出异常;基本上是无法打开文件
#ImportError 无法引入模块或包;基本上是路径问题或名称错误
#IndentationError 语法错误(的子类) ;代码没有正确对齐
#IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
#KeyError 试图访问字典里不存在的键
#KeyboardInterrupt Ctrl+C被按下
#NameError 使用一个还未被赋予对象的变量
#SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
#TypeError 传入对象类型与要求的不符合
#UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
#ValueError 传入一个调用者不期望的值,即使值的类型是正确的
#SystemExit 解释器请求退出
#Exception 万能异常,捕获任意异常
try except
try:
被检测的代码块
except 异常类型:
try中一旦检测到异常,就执行这个位置的逻辑
eg:
try:
train_net(net=net,
epochs=args.epochs,
batch_size=args.batchsize,
lr=args.lr,
device=device,
img_scale=args.scale,
val_percent=args.val / 100)
except KeyboardInterrupt:
torch.save(net.state_dict(), 'INTERRUPTED.pth')
logging.info('Saved interrupt')
try:
sys.exit(0)
except SystemExit:
os._exit(0)
try finally
def dealwith_file():
try:
f = open('file',encoding='utf-8')
for line in f:
int(line)
return True
except Exception as e:
print(e)
return False
finally:
'''不管try语句中的代码是否报错,都会执行finally分支中的代码'''
'''去完成一些连接操作的收尾工作'''
print('finally 被执行了')
f.close()
ret = dealwith_file()
print(ret)
assert
Python assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常。
assert newW > 0 and newH > 0, 'Scale is too small'
raise
raise NotImplemented
NotImplemented是Python在内置命名空间中的六个常数之一。其他有False、True、None、Ellipsis 和 debug。和 Ellipsis很像,NotImplemented]能被重新赋值(覆盖)。对它赋值,甚至改变属性名称, 不会产生 SyntaxError。所以它不是一个真正的“真”常数。当然,我们应该永远不改变它。
NotImplemented 是个特殊值,它能被二元特殊方法返回(比如__eq__()、__lt__() 、__add__() 、__rsub__()
等),表明某个类型没有像其他类型那样实现这些操作。同样,它或许会被原地处理(in place)的二元特殊方法返回(比如__imul__()、__iand__()
等)。还有,它的实际值为True:
>>> bool(NotImplemented)
True
>>> b1 == a1
Could not compare B against the other class
Comparing an A with a B
True
这就是返回了NotImplemented的所做的。NotImplemented告诉运行时,应该让其他对象来完成某个操作。在表达b1 == a1中,b1.__eq__(a1)
返回了NotImplemented,这说明Python试着用a1.__eq__(b1)
。由于a1足够可以返回True,因此这个表达可以成功。如果A中的__eq__()
也返回NotImplemented,那么运行时会退化到使用内置的比较行为,即比较对象的标识符(在CPython中,是对象在内存中的地址)。
注意:如果在调用b1.__eq__(a1)
时抛出NotImpementedError,而不进行处理,就会中断代码的执行。而NotImplemented无法抛出,仅仅是用来进一步测试是否有其他方法可供调用。
各种包
模块与包
模块: 一般来说, 单个py文件就叫模块(module), 调用这个模块直接使用import 模块名
即可, 也可以使用from 模块名 import 函数名/变量名/类名
和from 模块名 import *
包: 当我们写了几个相近的py文件后, 想要集成起来给别人使用. 这时候就需要用到我们的包了。包就是为了多个py文件打包起来访问的东西. 只要在包里面放一个__init__.py
文件, 在__init__.py
文件import包里面的模块(py文件)
, 就可以实现import 包名
,实现对多个模块的调用。
packet
---__init__.py
---a.py
---b.py
import packet.a #用.
import packet #导入的是__inti__.py里面导入的
事实上,当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类。因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。
__all__
除此之外,还可以借助模块提供的 __all__
变量,该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。通过在模块文件中设置 __all__
变量,当其它文件以from 模块名 import *
的形式(仅此种形式)导入该模块时,该文件中只能使用 __all__
列表中指定的成员。
假设有如下目录结构:
-- dir0
| file1.py
| file2.py
| dir3
| file3.py
| dir4
| file4.py
1.导入同级模块
如在file1.py
中想导入file2.py
,注意无需加后缀".py"
:
import file2
# 使用file2中函数时需加上前缀"file2.",即:
# file2.fuction_name()
2.导入下级模块
方式一:
# 需要一直带着dir3,书写比较麻烦,因此建议起一个别名,例如df3
import dir3.file3
# import dir3.file3 as df3
方式二:
# 在dir3下新建一个__init__.py
-- dir0
| file1.py
| file2.py
| dir3
| __init__.py
| file3.py
| dir4
| file4.py
import dir3 # 导入的是__init__.py中导入的
3.导入上级模块
要导入上级目录下模块,可以使用sys.path
,如在file4.py
中想引入import
上级目录下的file1.py
:
import sys
sys.path.append("/home/dch")
import file1
# sys.path特指模块的查询路径的列表,初始化是从环境变量PYTHONPATH。
#不知道怎么加可以先print(sys.path)
# 运行结果如下所示,该python脚本在调用模块的时候可以按照下面的路径依次查找python模块,最后一行是我们加入的第三方的python程序模块的路径。
['C:\\Users\\syd\\Desktop\\program',
'D:\\Installation_program\\anaconda\\python36.zip',
'D:\\Installation_program\\anaconda\\DLLs',
'D:\\Installation_program\\anaconda\\lib',
'D:\\Installation_program\\anaconda',
'D:\\Installation_program\\anaconda\\lib\\site-packages',
'D:\\Installation_program\\anaconda\\lib\\site-packages\\win32',
'D:\\Installation_program\\anaconda\\lib\\site-packages\\win32\\lib',
'D:\\Installation_program\\anaconda\\lib\\site-packages\\Pythonwin',
'/home/syd/GAN']
#或者
export PYTHONPATH=/home/pi/my_lib
math
# 返回x的阶乘值。如果x不是整数或者为负数,抛出ValueError。
math.factorial(x)
# 返回e的x次方
math.exp(x)
tqdm
from tqdm import tqdm
for fname in tqdm(os.listdir(input_dir)):
#fname就是os.listdir(input_dir)的每一项
#tqdm(range(i))可以使用trange(i)替换
另一种调用方式:
with tqdm(total=n_train, desc=f'Epoch {epoch + 1}/{epochs}', unit='img') as pbar:
#使用with的好处是不用手动关闭pbar
文档
class tqdm():#装饰一个迭代器对象,返回一个表现得就像原来可迭代的迭代器;但是在每次值被请求时就打印一个动态的更新进度条
def __init__(self, iterable=None, desc=None,#进度条的前缀
total=None,
leave=True,#默认为True,即在迭代的最后保持进度条的所有踪迹,简单来说就是会把进度条的最终形态保留下来。
#否则最后进度条消失
file=None, ncols=None, mininterval=0.1,
maxinterval=10.0, miniters=None, ascii=None, disable=False,
unit='it',
#用来定义每个迭代单元的字符串。默认为"it",表示每个迭代;在下载或解压时,设为"B",代表每个“块”。
#显示速度时,是1s/it还是1s/B,在时间后面
unit_scale=False, dynamic_ncols=False,
smoothing=0.3, bar_format=None, initial=0, position=None,
postfix=None, unit_divisor=1000):
pbar.set_description('Epoch %d' % (i+1))
#与前面tqdm构造时的desc相同
def set_postfix(self, ordered_dict=None, refresh=True, **kwargs):
#设置/修改后缀,在速度后面
#ordered_dict是传入有序字典,后边的**kwargs则是对ordered_dict的覆盖和补充。输出为a=1这种形式。
def update(self, n=1):
#手动更新进度条,对流streams有用,比如读文件
#n:int, optional 添加到迭代内部计数器的增长数[default:1]
os
os模块提供了一个统一的操作系统接口函数,os模块能在不同操作系统平台如nt,posix中的特定函数间自动切换,从而实现跨平台操作。
a=os.path.join("datasets", "lifesat", "")
#连接两个路径
print(a)
#datasets\lifesat\
os.makedirs()
#递归的创建文件目录
#exist_ok:是否在目录存在时触发异常。
#如果exist_ok为False(默认值),则在目标目录已存在的情况下触发FileExistsError异常;
#如果exist_ok为True,则在目标目录已存在的情况下不会触发FileExistsError异常。
os.listdir(path)
#获取指定目录下的所有文件和目录 包括隐藏文件
#eg:a/b.txt,listdir(a),输出b.txt,没有/之前的
os.path.splitext()
#分离文件名与扩展名 eg:
path_01='E:\STH\Foobar2000\install.log'
path_02='E:\STH\Foobar2000'
res_01=os.path.splitext(path_01)#返回的是tuple
res_02=os.path.splitext(path_02)
print(root_01)
print(root_02)
#('E:\\STH\\Foobar2000\\install', '.log')
#('E:\\STH\\Foobar2000', '')
#返回文件名和路径名
a = "D:\\class_datas\\master\\semanticseg\\Pytorch-UNet\\train.py"
print(os.path.basename(a))
print(os.path.dirname(a))
#train.py
#D:\class_datas\master\semanticseg\Pytorch-UNet
os.environ['CUDA_VISIBLE_DEVICES']
#environ是一个字符串所对应环境的映像对象。举个例子来说,environ['HOME']就代表了当前这个用户的主目录。
#CUDA——VISIBLE
os.path.expanduser(root)
#主要的功能在于把路径中的~转化为user目录,一般使用在Linux系统,代码中设置了某些路径的环境变量的时候。
#改变当前脚本工作目录到path
os.chdir(path)
#用于检验文件是否存在。
os.path.exists(file/dir)
# 删除文件
os.remove(file)
# 获取当前工作目录,再出现文件路径问题的时候用这个可太好用了
os.getcwd()
# 修改文件名
os.rename(filename,newname)
# 扫描某个指定目录下所包含的子目录和文件 https://zhuanlan.zhihu.com/p/149824829
for curDir, dirs, files in os.walk("test"):# 递归地输出当前目录,当前目录下的文件夹名字,当前目录下的文件名字
# 禁止hash随机化,使得实验可复现
os.environ['PYTHONHASHSEED'] = str(seed)
pathlib
面向对象的文件系统路径,对于底层的路径字符串操作,你也可以使用 os.path
模块。但是pathlib
可能更好用。
from pathlib import Path #老版本是pathlib,新版本是pathlib2,完美兼容老版本
# 文件名操作
from pathlib2 import Path
# 返回目录中最后一个部分的扩展名
example_path = Path('/Users/Anders/Documents/abc.gif')
print(example_path.suffix)
# 输出如下:
# .gif
# 返回目录中多个扩展名列表
example_paths = Path('/Users/Anders/Documents/abc.tar.gz')
print(example_paths.suffixes)
# 输出如下:
# ['.tar', '.gz']
# 返回目录中最后一个部分的文件名(但是不包含后缀)
example_path = Path('/Users/Anders/Documents/abc.gif')
print(example_path.stem)
# 输出如下:
# abc
# 返回目录中最后一个部分的文件名
example_path = Path('/Users/Anders/Documents/abc.gif')
print(example_path.name)
# 输出如下:
# abc.gif
# 替换目录最后一个部分的文件名并返回一个新的路径
new_path1 = example_path.with_name('def.gif')
print(new_path1)
# 输出如下:
# /Users/Anders/Documents/def.gif
# 替换目录最后一个部分的文件名并返回一个新的路径
new_path2 = example_path.with_suffix('.txt')
print(new_path2)
# 输出如下:
# /Users/Anders/Documents/abc.txt
shutil
https://liujiangblog.com/course/python/61
shutil模块是对os模块的补充,主要针对文件的拷贝、删除、移动、压缩和解压操作。
sys
sys模块主要是针对与Python解释器相关的变量和方法,不是主机操作系统。
# 退出Python程序,exit(0)表示正常退出。当参数非0时,会引发一个SystemExit异常,可以在程序中捕获该异常
sys.exit(n)
# 详解如下
# https://www.cnblogs.com/hls-code/p/15337302.html
sys.path.append()
argparse
python自带的命令行参数解析包,可以用来方便地读取命令行参数,当你的代码需要频繁地修改参数的时候,使用这个工具可以将参数和代码分离开来,让你的代码更简洁,适用范围更广。它解析sys.argv中的参数。
一篇比较好的个人博客 add_argument里的各个参数在这看
可选参数、必需参数和位置参数
#位置参数
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name')
parser.add_argument('age')
args = parser.parse_args()
print(f'{args.name} is {args.age} years old')
#$ positional_arg.py Peter 23
#Peter is 23 years old
#可选参数
import argparse
# help flag provides flag help
# store_true actions stores argument as True
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='store_true', help="shows output")
#具有两个选项的参数,short -o和long --output,如果设置为store_true,则将参数存储为True。
#参数一旦存在,则action将其设置为true,如果加上default时,未设置就是default起作用,否则就是action的相反。
args = parser.parse_args()
if args.output:#存在该参数,则显示一些输出。
print("This is some output")
#可选参数推断规则 --foo-bar -> foo_bar -x -> x
#可将可选参数变为必需参数
parser.add_argument('--name', required=True)#设置required为True
add_argument的各种参数
#metavar参数可以让命令的帮助信息更好看一些!
#除此之外,对于有nargs参数的命令行参数,可以用metavar来设置每一个具体的参数的名称:
parser = argparse.ArgumentParser(prog='PROG')
#prog代替了test.py
parser.add_argument('-x', nargs=2)
parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
parser.print_help()#这个可以输出帮助信息
#输出如下
usage: PROG [-h] [-x X X] [--foo bar baz]
optional arguments:
-h, --help show this help message and exit
-x X X
--foo bar baz
>>>python train.py -h
#可以显示提示信息,和上面的parser.print_help()一样
parser = argparse.ArgumentParser(description='Train the UNet on images and target masks',
#usage下面加了一行描述信息
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
#提示信息格式
#创建一个解析器
parser.add_argument('-l', '--learning-rate', metavar='LR', type=float, nargs='?', default=0.0001,
help='Learning rate', dest='lr')
#添加一个新参数
#argparse默认的变量名是--或-后面的字符串
#但是你也可以通过dest=xxx来设置参数的变量名,然后在代码中用args.xxx来获取参数的值。
#nargs=x
#x的值 含义
#N 参数的绝对个数(例如:3)
#'?' 0或1个参数
#'*' 0或所有参数
#'+' 所有,并且至少一个参数
# argparse.REMAINDER 所有剩余的参数,均转化为一个列表赋值给此项,通常用此方法来将剩余的参数传入另一个parser进行解析
arg=parser.parse_args()
#如果dataset之前没定义,那么就是给arg添加了一个新属性dataset
arg.dataset=#某个值
# 对于目前的parser未知的argument,不报错,而是将多出来的部分保存起来,留到后面使用。之后给parser addargument之后,可以在parser.parse_known_args()
# 或者parser.parse_args()
opt, unparsed = parser.parse_known_args()
# 设置一些参数的默认值,且会覆盖parser.addargument()中的default设置
parser.set_defaults(foo='test')
# get_defaults()方法可以获取add_argument()和set_defaults()中设置的默认值
parser.get_default('air')
修改args来不用命令行使用
# jupyter也可以使用
import sys
sys.argv=['damaenet_res101_40e_DarkZ.ipynb','--num-steps','48320','--help-info','wokecheng+mae']
logging
logging模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统。
logging模块提供了两种记录日志的方式:
- 第一种方式是使用logging提供的模块级别的函数
- 第二种方式是使用Logging日志系统的四大组件
其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。
logging模块与log4j的机制是一样的,只是具体的实现细节不同。模块提供logger,handler,filter,formatter。
logger:提供日志接口,供应用代码使用。logger最常用的操作有两类:配置和发送日志消息。可以通过logging.getLogger(name)获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象。
handler:将日志记录(log record)发送到合适的目的地(destination),比如文件,socket等。一个logger对象可以通过addHandler方法添加0到多个handler,每个handler又可以定义不同日志级别,以实现日志分级过滤显示。用于将日志记录发送到指定的目的位置
filter:提供一种优雅的方式决定一个日志记录是否发送到handler。提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略)
formatter:指定日志记录输出的具体格式。formatter的构造方法需要两个参数:消息的格式字符串和日期字符串,这两个参数都是可选的。
logging模块提供的模块级别的那些函数实际上也是通过这几个组件的相关实现类来记录日志的,只是在创建这些类的实例时设置了一些默认值。
#四大组件的方法
logger = logging.getLogger()
#日志对象,logging模块中最基础的对象
logger.setLevel(logging.INFO)
#设置日志级别
BASIC_FORMAT = "%(asctime)s: %(message)s"
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
formatter = logging.Formatter(BASIC_FORMAT, DATE_FORMAT)
#日志记录输出的具体格式
chlr = logging.StreamHandler()#就好比windows的console,打印在CMD
chlr.setFormatter(formatter)#设置chlr handler的格式
chlr.setLevel('INFO')#设置chlr handler的级别,INFO级别及以上输出
fhlr = logging.FileHandler(osp.join(final_log_path, log_file))#文件日志,打印在文件里
fhlr.setFormatter(formatter)#设置格式
#文件没有setLevel,我怀疑就是使用logger的Level
logger.addHandler(chlr)
logger.addHandler(fhlr)
#将相应的handler添加到logger上
return logger
#之后使用就是eg:logger.debug(message)
#模块级别
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s')
#basicConfig:对root logger进行一次性配置
#level:指定日志器的日志级别,>=INFO级别的日志才会输出
#format:指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。
# eg WARNING:root:This is a warning log.
#如果不设置basicConfig默认级别为Warning
#filename:指定使用指定的文件名而不是StreamHandler创建FileHandler。
#filemode:指定打开文件的模式,如果指定了filename(如果文件模式未指定,则默认为'a')。
#datefmt:使用指定的日期/时间格式。
#handlers:如果指定,这应该是一个已经创建的处理程序的迭代器添加到根记录器。任何尚未设置格式化程序的处理程序都将被分配在此函数中创建的默认格式化程序。
logging.info(f'Using device {device}')
#创建一条严重级别为INFO的日志记录,也可这么写logging.log(logging.INFO, "This is a info log.")
格式字符串字段
%(levelname)s#该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
%(name)s#所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
%(message)s#日志记录的文本内容,通过 msg % args计算得到的
%(asctime)s#字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
glob
glob是python自带的一个操作文件的相关模块,由于模块功能比较少,所以很容易掌握。用它可以查找符合特定规则的文件路径名。使用该模块查找文件,只需要用到: *
?
[]
三个匹配符;
#”*”匹配0个或多个字符;
#”?”匹配单个字符;
#”[]”匹配指定范围内的字符,如:[0-9]匹配数字。
glob.glob
#返回所有匹配的文件路径列表。它只有一个参数pathname,定义了文件路径匹配规则,这里可以是绝对路径,也可以是相对路径。
#python的glob模块可以对文件夹下所有文件进行遍历,并保存为一个list列表
mask_file = glob.glob(self.masks_dir + idx + self.mask_suffix + '.*')
time
time.strftime(format[,t])
#将struct_time类型的时间转换为format参数指定格式的字符串。
#format:指定转换时间的字符串格式。
#t:struct_time类型的时间,如果不填默认为当前时间(即time.localtime()返回的时间)
# 计时 分析网络运行的操作时可太好用了
start=time.perf_counter()
end = time.perf_counter()
print(end-start)
PIL
Image
Image.crop(left, up, right, below)
#切四刀获得一个新的小块
#left:与左边界的距离
#up:与上边界的距离
#right:还是与左边界的距离
#below:还是与上边界的距离
img = img.resize((ow, oh), Image.BILINEAR)
#Image.NEAREST:最近邻插值
#Image.BILINEAR:双线性插值
#Image.BICUBIC:双三次插值
#Image.ANTIALIAS:面积插值
out = im.rotate(45) #45°旋转
out = im.transpose(Image.FLIP_LEFT_RIGHT) #水平翻转
out = im.transpose(Image.FLIP_TOP_BOTTOM) #垂直翻转
out = im.transpose(Image.ROTATE_90) # 90
out = im.transpose(Image.ROTATE_180) #180°顺时针翻转
out = im.transpose(Image.ROTATE_270) #270°顺时针翻转
ImageOps
PIL的一些图像处理操作
ImageOps.expand(image, border=0, fill=0)⇒ image
#eg:ImageOps.expand(img, border=(0, 0, padw, padh), fill=0)
#按照变量border的四元组,在图像的左、上、右、下四个边,使用给定的颜色填充相应的行和列。
random
import random
#随机生成[0,1.0)的浮点数
print(random.random())
#用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b(闭区间)
random.randint(a, b)
# 从sequence中随机选出一个元素,参数sequence表示一个有序类型
random.choice(sequence)
# 用于将一个列表中的元素随机打乱
L=[1,2,3,4,5,6,7]
random.shuffle(L)
requests
get()
get()
方法发出 GET 请求,它获取由给定 URL 标识的文档。
import requests as req
a = req.get("http://dchlovestudy.xyz/")
print(a.text)
输出如下:
返回的对象a
类型为<class 'requests.models.Response'>
,该对象的属性status_code
返回相应的HTTP代码,例如200或404。200 是成功 HTTP 请求的标准响应,而 404 则表明找不到所请求的资源。
self.sess = requests.Session()
会话对象让你能够跨请求保持某些参数。
urllib
Python urllib 库用于操作网页 URL,并对网页的内容进行抓取处理。
urllib 包 包含以下几个模块:
- urllib.request - 打开和读取 URL。
- urllib.error - 包含 urllib.request 抛出的异常。
- urllib.parse - 解析 URL。
- urllib.robotparser - 解析 robots.txt 文件。
urllib.parse
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
# urlstring为字符串的url地址
# scheme为协议类型
# allow_fragments参数为false,则无法识别片段标识符。相反,它们被解析为路径、参数或查询组件的一部分,并且fragment在返回值中设置为空字符串。
from urllib.parse import urlparse
o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(o)
# ParseResult(scheme='https', netloc='www.runoob.com', path='/', params='', query='s=python+%E6%95%99%E7%A8%8B', fragment='')
# 从结果可以看出,内容是一个元组,包含 6 个字符串:协议,位置,路径,参数,查询,判断。
o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(o.scheme)
# https

collections
defaultdict
使用dict
时,如果引用的Key不存在,就会抛出KeyError
。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回默认值
'N/A'
dict1 = defaultdict(int)# 0
dict2 = defaultdict(set)# set()
dict3 = defaultdict(str)#
dict4 = defaultdict(list)# []
注意默认值是调用函数返回的,而函数在创建defaultdict
对象时传入。除了在Key不存在时返回默认值,defaultdict
的其他行为跟dict
是完全一样的。
defaultdict
传入的函数是工厂函数:
工厂函数看上去有点像函数,实质上他们是类,当你调用他们时,实际上是生成了该类型的一个实例,就像工厂生产货物一样。
OrderedDict
使用dict
时,Key是无序的。在对dict
做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict
:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
模块collections中的子类,使字典的迭代顺序就是插入的顺序
注:从python3.6开始,普通的字典也是有序的了,即按照插入的顺序迭代。字典也是有顺序的,顺序就是插入的顺序。
namedtuple
namedtuple
是一个函数,它用来创建一个自定义的tuple
对象,并且规定了tuple
元素的个数,并可以用属性而不是索引来引用tuple
的某个元素。
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2
deque
双端队列(double-ended queue)的缩写,由于两端都能编辑,deque既可以用来实现栈(stack)也可以用来实现队列(queue)。

class collections.deque([iterable[, maxlen]])
q = collections.deque([1, 2, 3, 4])
print(5 in q) # False
print(1 in q) # True
Counter
Counter(计数器)是对字典的补充,用于追踪值的出现次数。
Counter是一个继承了字典的类(Counter(dict))
。(就是我想实现的那个!!!!😂)
import collections
obj = collections.Counter("asfsfsa")# 用来方便的进行计数
obj
>>>Counter({'a': 2, 'f': 2, 's': 3})
重写了加和减
def __sub__(self, other):
''' Subtract count, but keep only results with positive counts.
>>> Counter('abbbc') - Counter('bccd')
Counter({'b': 2, 'a': 1})
'''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
newcount = count - other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count < 0:
result[elem] = 0 - count
return result
functools
https://docs.python.org/3/library/functools.html
functools 模块用于高阶函数:接受函数为参数或返回其他函数的函数。 通常,出于此模块的目的,任何可调用对象都可以视为函数。
functools.partial
functools.partial
的作用和tensorflow
的slim
很像,主要作用就是简化函数,更少更灵活的函数参数调用。functools.partial
可以让我们通过包装的方法,减少你的函数参数。
functools.partial用于部分应用一个函数,它基于一个函数创建一个可调用对象,把原函数的某些参数固定,调用时只需要传递未固定的参数即可。
import functools
def add(a, b):
print("当前结果值", a+b)
add = functools.partial(add, 1)
add(2)
# 输出
# 当前结果值3
# 核心源码
class partial:
"""New function with partial application of the given arguments
and keywords.
"""
__slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
def __new__(*args, **keywords):
if not args:
raise TypeError("descriptor '__new__' of partial needs an argument")
if len(args) < 2:
raise TypeError("type 'partial' takes at least one argument")
# 类实例,原函数,被固定的参数
cls, func, *args = args
if not callable(func):
raise TypeError("the first argument must be callable")
args = tuple(args)
if hasattr(func, "func"):
args = func.args + args
tmpkw = func.keywords.copy()
tmpkw.update(keywords)
keywords = tmpkw
del tmpkw
func = func.func
# 实例化partial对象,将传入的函数和参数设置为当前对象的属性
self = super(partial, cls).__new__(cls)
self.func = func
self.args = args
self.keywords = keywords
return self
def __call__(*args, **keywords):
if not args:
raise TypeError("descriptor '__call__' of partial needs an argument")
self, *args = args
newkeywords = self.keywords.copy()
newkeywords.update(keywords)
return self.func(*self.args, *args, **newkeywords)
reduce
# reduce() 函数会对参数序列中元素进行累积。
# 函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,
# 得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
from functools import reduce
def add(x, y) : # 两数相加
return x + y
sum1 = reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
sum2 = reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
print(sum1)
print(sum2)
lru_cache()
itertools
为高效循环创建迭代器的函数
该模块实现了许多受 APL、Haskell 和 SML 构造启发的迭代器构建块。 每个都以适合 Python 的形式重铸。该模块标准化了一组核心的快速、高效的内存工具,这些工具本身或组合使用。 它们一起形成了一个“迭代器代数”,使得在纯 Python 中简洁有效地构建专用工具成为可能。
这些工具及其内置的对应物也可以很好地与operator模块中的高速功能配合使用。 例如,乘法运算符可以映射到两个向量以形成有效的点积:sum(map(operator.mul, vector1, vector2))。
https://docs.python.org/3/library/itertools.html
直接看文档,文档写的太清楚了
# accumulate用来求前缀和真是太方便了
accumulate([1,2,3,4,5])# --> 1 3 6 10 15
accumulate([1,2,3,4,5], initial=100)# --> 100 101 103 106 110 115
accumulate([1,2,3,4,5], operator.mul)# --> 1 2 6 24 120
json
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写。
json.loads
用于解码 JSON 数据。该函数返回 Python 字段的数据类型。
#!/usr/bin/python
import json
jsonData = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
text = json.loads(jsonData)
print(text)
#{u'a': 1, u'c': 3, u'b': 2, u'e': 5, u'd': 4}
json.dump
将python中的对象转化成json储存到文件中
json.dump(obj,# 转化成json的对象。
fp,# 文件指针
*, skipkeys=False,
ensure_ascii=True,# 输出保证所有传入的非ASCII字符都被转义;为false,则这些字符将按原样输出。
check_circular=True, allow_nan=True, cls=None,
indent=None,# 如果缩进是非负整数或字符串,那么 JSON 数组元素和对象成员将使用该缩进级别进行漂亮打印
# 用正整数缩进每级缩进多少个空格。
separators=None, default=None, sort_keys=False, **kw)
timm
PyTorch Image Models (timm)是一个图像模型(models)、层(layers)、实用程序(utilities)、优化器(optimizers)、调度器(schedulers)、数据加载/增强(data-loaders / augmentations)和参考训练/验证脚本(reference training / validation scripts)的集合,目的是将各种SOTA模型组合在一起,从而能够重现ImageNet的训练结果。to_2tuple
:将传进来的x变成一个(x,x)的tuple
DropPath
:将深度学习模型中的多分支结构随机”删除“
# 假设在前向传播中有如下代码
x = x + self.drop_path(self.mlp(self.norm2(x)))
那么在drop_path分支中,每个batch有drop_prob的概率样本在self.mlp(self.norm2(x))不会”执行“,会以0直接传递。
copy
提到copy包,就不得不提浅拷贝和深拷贝了~
import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
# 浅拷贝,对will的修改也会影响到wilber
wilber = copy.copy(will)
# 另一个例子
b = [1,2,3]
a = []
a.append(b)
# a:[[1,2,3]] 现在修改b,a也会改变,所以也是类似浅拷贝,只是把b的引用添加到a里了
总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:
- 使用切片[:]操作
- 使用工厂函数(如list/dir/set)
- 使用copy模块中的copy()函数
如果要深拷贝,可以使用copy.deepcopy()进行深拷贝
heapq
q是队列的意思,堆本来就是一种优先队列,heapq里的堆是小根堆。
Python中heapq 模块是小根堆。实现大根堆方法: 小根堆的插入和弹出操作均将元素取反即可。
要创建一个堆,可以使用list来初始化为[]
,或者你可以通过一个函数heapify()
,来把一个list转换成堆。
# 将item的值加入heap中,保持堆的不变性。
heapq.heappush(heap, item)
# 弹出并返回heap的最小的元素,保持堆的不变性.如果堆为空,抛出IndexError 。
# 使用 heap[0],可以只访问最小的元素而不弹出它。
heapq.heappop(heap)
# 将item放入堆中,然后弹出并返回heap的最小元素。该组合操作比先调用heappush()再调用heappop()运行起来更有效率。
heapqpushpop(heap,item)
# 将list x转换成堆,原地,线性时间内。
heapq.heapify(x)
# 从 iterable 所定义的数据集中返回前 n 个最大元素组成的列表。
# 如果提供了 key 则其应指定一个单参数的函数,用于从 iterable 的每个元素中提取比较键 (例如 key=str.lower)。
heapq.nlargest(n, iterable, key=None)
heapq.nsmallest(n, iterable, key=None)
heapq.heapreplace(heap, item)
#弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发 IndexError。
#这个单步骤操作比 heappop() 加 heappush() 更高效,并且在使用固定大小的堆时更为适宜。 pop/push 组合总是会从堆中返回一个元素并将其替换为 item。
# 返回的值可能会比添加的 item 更大。 如果不希望如此,可考虑改用 heappushpop()。 它的 push/pop 组合会返回两个值中较小的一个,将较大的值留在堆中。
heapq模块可以接受元组对象,默认元组的第一个元素作为priority
,即按照元组的第一个元素构成小根堆。
bisect
[bisection n.二等分]该模块支持以排序顺序维护列表,而无需在每次插入后对列表进行排序。 对于具有昂贵比较操作的长列表项目,这可能是对更常见方法的改进。 该模块被称为 bisect,因为它使用基本的二分算法来完成它的工作。 源代码作为算法的工作示例可能是最有用的(边界条件已经正确!)。
想要使用二分搜索/二分查找但又懒得写肿么办?!当然是使用 bisect 模块 啦 ~~ 顾名思义,它是实现了 二分 (bisection) 算法的模块,能够保持序列 sequence 顺序不变 的情况下对其进行二分查找和插入,适合用于降低对冗长序列查找的时间成本。当然,通过 “以空间换时间” 的方式也是可行的,例如用于构造 hashmap 的 Counter 类 (关于 Counter 模块详见 链接)。然而,本文的焦点是使用 bisect 模块 “凭查找方式降时间”。
importlib
Python 的模块载入机制。模块包含实现 Python 导入机制的函数,用于在包和模块中加载代码。 它是动态导入模块的一个访问点,在编写代码时需要导入的模块名称未知的情况下很有用(例如,对于应用程序的插件或扩展)。
importlib.import_module(name, package=None)
├── clazz
│ ├── __init__.py
│ ├── a.py
│ └── b.py
└── main.py
a.py:
def show():
print("show A")
b.py:
def show():
print("show B")
main.py:
import importlib
# 绝对导入
a = importlib.import_module("clazz.a")
a.show()
# show A
# 相对导入
b = importlib.import_module(".b", "clazz")
b.show()
# show B
xlrd/xlwt
# 返回了一个Book对象
data3 = xlrd.open_workbook('../datas/net1//yewu_net1_300.xlsx')
# 获取sheet0
table = data3.sheets()[0]
# 获取行数和列数
row=table.nrows
col=table.ncols
# 获取单元格的值 <class 'xlrd.sheet.Cell'> Cell对象
table.cell(i, n).value
scipy
SciPy 是一个开源的 Python 算法库和数学工具包。
Scipy 是基于 Numpy 的科学计算库,用于数学、科学、工程学等领域,很多有一些高阶抽象和物理模型需要使用 Scipy。
SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
IPython
from Ipython import display as ipd
ipd.display(dataframe)
fractions
https://docs.python.org/zh-cn/3/library/fractions.html
分数库
pdb
warning
https://docs.python.org/zh-cn/3/library/warnings.html
警告信息的控制-通常以下情况会引发警告:提醒用户注意程序中的某些情况,而这些情况(通常)还不值得触发异常并终止程序。例如,当程序用到了某个过时的模块时,就可能需要发出一条警告。
# 通过警告过滤器来控制是否发出警告信息
import warnings
warnings.filterwarnings('ignore') #忽略警告信息
mpi4py的安装
sudo apt install libopenmpi-dev
conda install mpi4py #pip不行