命令行及环境配置
PIP参数
- 波浪线tilde equals (~=),选择包的当前大版本的最高子版本 (Stackoverflow)
example:
mock-django~=0.6.10It will select the latest version of the package, greater than or equal to 0.6.10, but still in the 0.6.* version, so it won’t download 0.7.0 for example.
检查安装的模块版本
- 代码
import sys
import pkg_resources
if __name__ == '__main__':
m_name = sys.argv[1]
try:
v = pkg_resources.get_distribution(m_name).version
print("{}'s version is: {}".format(m_name, v))
except:
print("No such a module installed.")虚拟环境venv
- 如果有多个Python版本(如Ubuntu20.04有默认的Python 3.8并额外安装Python 3.12),对于3.12版需安装
sudo apt install python3.12-venv。以下以3.12为例 - 创建虚拟环境
python3.12 -m venv myenv- Windows下激活虚拟环境的脚本
@echo off
cmd /k ".\myenv\Scripts\activate.bat"- Linux下激活虚拟环境的脚本
source ./myenv/bin/activate- 如果创建了虚拟环境后,默认的Python就为对应版本
- 停用虚拟环境
deactivate - 安装OpenCV
pip install opencv-contrib-python
基本语法
Ellipsis (”…“)
- singleton Ellipsis object A placeholder for not-yet-written code,个人认为是比pass更好用的平替
Python中的Null类型 — None/NoneType
- Python中的Null类型为None,可以使用
if foo is None来判断,注意is和==的区别,参考[[4.software/programming_language/python/00.python_basic#-和is用于比较|==和is用于比较]]
','的拆包
拆包符号的使用
拆包符号的运算优先级
- 拆包中不能放入连续的运算,
','前后的变量是同时完成运算(可以认为是并行),没有先后运算的时序关系,如输出结果为a, b = 1, 2 a, b = 2, a+1a=2,b=2,进行b的运算时并没有采用更新值,而是用之前初始化的值
== 和is用于比较
a==b用于比较两个的值是否相等,a is b比较a是否就是b(简单理解就是和b完全一致,不存在0也可以认为是False、1也可以认为是True的情况),举例:
| a的值 | 运算 | 结果 |
|---|---|---|
| a=0 | a==False | True |
| a=0 | a is False | False |
| a=1 | a==False | False |
| a=1 | a==True | True |
| a=1 | a is True | False |
| a=2 | a==True | False |
判断列表是否存在,或是否为空
x=None | x=[] | x=[1,2,3] | |
|---|---|---|---|
if x is None | True | False | False |
if not x | True | True | False |
if not (x is None) | False | True | True |
if x is not None | False | True | True |
None,False,空字符串"",0,空列表[],空字典{},空元组()都相当于False,因此if not x不能对其进行区分if x is not []不能用来判断空列表!
列表list及相关使用细节
遍历列表并删除满足某个条件的数据
- 从后向前遍历,使用
del()
a = [1,2,3,4,5,6]
for i in range(len(a)-1,-1,-1):
if a[i] %2 == 1:
del(a[i])多维列表根据某个位置的元素进行排序
- 使用
sort()函数和lambdareverse:False为升序排列,True为降序排列
your_list = [[1,3],[32,5],[23,2],[48,1],[48,4],[32,0]]
your_list.sort(reverse=True, key=lambda x: x[-1])输出为[[32, 5], [48, 4], [1, 3], [23, 2], [48, 1], [32, 0]]
两个list变量相互赋值,浅拷贝shallow copy与深拷贝deep copy
- 浅拷贝shallow copy对应C语言中按地址传递。深拷贝deep copy对应C语言中按值传递
- 如果声明了一个list类型变量
a,再通过b=a声明b时,是浅拷贝,之后对a的修改也会反应到变量中 - 类似情况如声明全零二维列表
- 如果在
a的基础上,声明一个列表,则为深拷贝,之后对a的修改,对于b没有影响,如a = [1,2,3] b = a+[0] ## b = [1,2,3,0] a[1] = [10] ## a = [1,10,3] ## b = [1,2,3,0]
批量修改列表中元素(如一个列表中每个元素均为np.array)
- 使用
__setitem__()方法a = [np.eye(4) for i in range(7)] [a[i].__setitem__((0, 3), 0.006) for i in range(3)]
声明全零二维列表
错误方法:
a = [[0]*m]*n这个列表中每一行[0]*m都指向同一实例,改变其中一个元素的值将同时改变每一行的值
这个方法相当于先声明了[0,0,0,...,0],再将其复制n次
正确方法
a = [ [0]*m for _ in range(n)]此二维列表中每个元素都是独立的
这个方法相当于每次都重新声明[0,0,0,...,0],共重复n次
Range()
- 在一个区间进行计数
range(x1,x2)的计数从x1开始,到x2-1结束,若生成列表,则为[x1, x1+1, x1+2, ..., x2-1]
- 倒序计数
range(n-1, -1, -1)从n-1反向计数至0
跳出多层循环
- 将多层循环包装为一个函数,使用
return - 抛出异常
class GetOutOfLoop(Exception): pass try: for i in ...: for j in ...: if ...: pass else: raise GetOutOfLoop except GetOutOfLoop: pass
用Ctrl+c跳出程序的主循环
- 一般方法
try:
while True:
do_something()
except KeyboardInterrupt:
pass
- ROS
while not rospy.is_shutdown():
...格式化输出
print/file.write的格式化输出
- 使用
print("your content here with {}".format(data)) - 指定整数或者小数的位数
print("data: {:3.4f}".format(your_float)) print("data: {:3.4}".format(your_float))若没有f,则为使用科学计数法表示
NumPy默认输出为科学计数法
如何导入在其他文件夹中的模块/同一子文件夹中的模块
- 假设当前脚本的结构为:
要在|->main.py |->utils/ |->vision/ |->rgb_process.py |->post_process.py |->control/ |->others/post_pocess.py中引用rgb_process中的object_mask类
sys.path.append('../../')
from utils.vision.rgb_process import object_mask配置与参数
Python的自带参数
调试Flag
- Python的
__debug__为调试flag,使用-O参数时执行优化(python -O test.py参数必须在中间),从而忽略__debug__中的内容,若无参数,则执行debug中的内容
if __debug__:
print('Debug ON')
else:
print('Debug OFF')添加命令行参数
- 示例
import argparse
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-init', '--init', default=False, help = 'initializing') # add_argument()指定程序可以接受的命令行选项
args = parser.parse_args() # parse_args()从指定的选项中返回一些数据
print(args)
print(args.init)
action:如果命令中包含参数-init,则其值将被设置为True(例如parser.add_argument('-init', '--init', action="store_true"),命令为python main.py -init)default:参数的默认值
跨文件的全局参数
- 参考python - Using global variables between files? - Stack Overflow
- 将所有全局变量移至一个文件,如
settings.py,这个文件里定义并且初始化所有全局变量
# settings.py def init(): global myList myList = []- 在
subfile中导入全局变量
# subfile.py import settings def stuff(): settings.myList.append('hey')init()只需要在main.py中调用,不需要在subfile或者其它文件中调用
# main.py import settings import subfile settings.init() # Call only once subfile.stuff() # Do stuff with global var print settings.myList[0] # Check the result - 将所有全局变量移至一个文件,如
This way, you achieve your objective while avoid initializing global variables more than once.
文件操作
获取文件夹下所有特定扩展名的文件名
- 方法一
def get_files(path, extention = '.txt'):
find_files = []
f_list = os.listdir(path)
for i in f_list:
if os.path.splitext(i)[-1] == extention:
find_files.append(i)
return find_files- 方法二
folder_path = "../../debug"
npz_files = [
f for f in os.listdir(folder_path)
if f.endswith(".npz") and os.path.isfile(os.path.join(folder_path, f))
]
时间、计时器与程序效率
用时间戳作为文件名
- 使用函数
time.strftime,注意time只能提供到秒,代码示例filename = time.strftime("%m-%d_%H-%M-%S", time.localtime(time.time())) - 使用
datetimefrom datetime import datetime filename = datetime.now().strftime("%m-%d_%H-%M-%S-%f")[:-3]
计时
- 方法一:单位为秒,代码示例
import timeit
start = timeit.default_timer()
## DO SOMETHING
stop = timeit.default_timer()
print("spent {}".format(stop-start))- 方法二:perf_count()输出的单位为秒,代码示例(乘以1000后转化为毫秒)
import time
start = time.perf_counter()
## DO SOMETHING
stop = time.perf_counter()
print("Runtime: {}ms".format((stop-start)*1000))程序效率
print()耗时的数量级为0.01ms- 尽量少使用循环,尤其是嵌套循环(如访问二维矩阵)