跳转python"小技巧"
用"""..."""
或'''...'''
实现多行注释
用#...
实现当行注释
"""
多行注释1
"""
'''
多行注释2
'''
# 当行注释
print("不是任何地方都需要写注释,适宜如下:新的语法点,重要细节结论,实现某个功能等")
关于python中的常量,并没有像C++里用const关键字来约束。但是我们平时通常用大写字母来命名常量,例如
PI = 3.14159265359
MAX_VALUE = 100
但事实上 PI 仍然是一个变量,Python 根本没有任何机制保证 PI 不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量 PI 的值,也没人能拦住你。
参考python基础_格式化输出(%用法和format用法)
# format()可以在{}的地方替换变量的值
# python3.6前的format方法:在()中写格式化的值
a,b = 0.2,0.1
print("a + b = {}".format(a+b))
# python3.6的format方法:str前写'f',在{}中写格式化的值
print(f"a + b = {a+b}")
---
a + b = 0.30000000000000004
a + b = 0.30000000000000004
name = "wangxiaoxi"
print('hello %s' % name)
num = 1.1
print("num = %.4f" % num)
---
hello wangxiaoxi
num = 1.1000
可以在字符串前面添加一个r
,表示一个原始的字符串。这样python就不会特殊处理字符串。
print("C\Lenovo\name")
print("C\\Lenovo\\name")
#如果不实用反斜杠转义,可以在字符串前面添加一个r,表示一个原始的字符串
print(r"C\Lenovo\name")
---
C\Lenovo
ame
C\Lenovo\name
C\Lenovo\name
power = 7 ** 2
power1 = 7.0 ** 2
print(f"7的2次方={power}")
print(f"7.0的2次方={power1}")
---
7的2次方=49
7.0的2次方=49.0
salary = 8050.53
# 向下取整:int()
salary_int = int(salary)
print(f"向下取整={salary_int}")
# 四舍五入:round(),第二个参数是保留小数点后多少位,默认是0
salary_round = round(salary,1)
print(f"四舍五入(保留一位小数)={salary_round}")
salary_round = round(salary)
print(f"四舍五入={salary_round}")
# 向上取整:math.ceil()
import math
salary_ceil = math.ceil(salary)
print(f"向上取整={salary_ceil}")
---
向下取整=8050
四舍五入(保留一位小数)=8050.6
四舍五入=8051
向上取整=8051
布尔类型与其他数据类型做与或非运算
python把0,空字符串’'和None看成False,其他数值和非空字符串都看成True。这里参考python布尔类型的短路运算https://www.cnblogs.com/chengjian-physique/p/7858496.html
好处是在写循环时,短路计算可以减少条件的判断,优化代码
a = True
print(a and 'a = T' or 'a = F')
#print(True and False or 'a = T')
print(a and '' or 'a = T')
print(a and 0 or 'a = T')
print(a and None or 'a = T')
---
a = T
a = T
a = T
a = T
# A: 修改字符串的大小写 title()、capitalize()、lower() 、upper()
str1 = "welcome to CHINA"
# 每个单词首字母大写
print(str1.title())
# 段落首写字母大写
print(str1.capitalize())
# 字符串转小写
print(str1.lower())
# 字符串转大写
print(str1.upper())
# 大写转小写,小写转大写 swapcase()
print(str1.swapcase())
---
Welcome To China
Welcome to china
welcome to china
WELCOME TO CHINA
WELCOME TO china
# B: 字符串字符判断
# String.isalnum()判断字符串中是否全部为数字或者英文,符合返回True,否则为False,如果有符号或空格也会返回False
print(str1.isalnum())
# String.isdigit()判断字符串是否全为整数
print(str1.isdigit())
---
False
False
# C: 字符串分割
str2 = "We will do better than ever before \n Fighting "
# 根据空格,换行符切分
print(str2.split())
# 根据指定字符切分
print(str2.split('n'))
# 根据换行符进行切分
print(str2.splitlines())
---
['We', 'will', 'do', 'better', 'than', 'ever', 'before', 'Fighting']
['We will do better tha', ' ever before \n Fighti', 'g ']
['We will do better than ever before ', ' Fighting ']
# - 字符串切片[start : end : step]
str4 = "Python"
print(str4[1:2])
print(str4[-1])
print(str4[-2])
print(str4[-2:])
print(str4[::-1])
---
y
n
o
on
nohtyP
# D: 字符串删除两边空白
# - 删除字符串两边的空白strip()、lstrip()、rstrip()
str3 = " just do it "
print(str3.strip())
print(str3.lstrip())
print(str3.rstrip())
---
just do it
just do it
just do it
# - 其他len()、replace()
# len()求字符串长度时,空格也算一个字符
print(len(str3))
print(str3.replace(' ','-'))
---
12
-just-do-it-
float(a)将变量a转化为浮点数,
int(b)将变量b转为整数
str©将变量c转为字符串
其中变量a,b,c为任意基本数据类型(数据结构不行)
and
= &
, or
= |
print(True and False)
False
print(True & False)
False
print(True or False)
True
print(True | False)
True
注意和Java对象类型转换区分开
rom pandas import read_csv
from pandas import Series
df = read_csv(
open(r"E://python/数据集/数据分析入门/data3.csv")
)
'''一列可作为Series,会自动添加缺失的索引'''
# 该语法会报错:Series s = df['name']
s = Series(df['name'])
type(df['name'])
1、函数要手动传self,方法不用传self。
2、在面向过程的程序设计里面,函数是基本单元,利于分工合作。
3、如果是一个函数,用类名去调用,如果是一个方法,用对象去调用。下面以列表操作为例子
'''E:列表的删除'''
#用del函数
del list[0]
print(f"新列表元素如下6:{list}")
---
新列表元素如下6:['小王', '小李子', '小张', '小红', '大表哥']
#用pop方法(有返回值,且默认删除末尾元素)
a = list.pop()
print(a)
print(f"新列表元素如下6:{list}")
---
新列表元素如下6:['小王', '小李子', '小张', '小红']
b = list.pop(0)
print(b)
print(f"新列表元素如下7:{list}")
---
新列表元素如下7:['小李子', '小张', '小红']
参考2. 内置函数
或者在Zeal
中搜索Built-in Functions
以map()
函数为例:map(function, iterable, ...)
其中第一个参数是函数(比如int()
内置函数),第二个参数是可迭代的对象(比如list对象)。
list_float = [0.78,8.5,9.6,2.3]
list_int = list(map(int,list_float))
print(list_int)
---
[0, 8, 9, 2]
def myfunction(name,age):
print(name,"的年龄为",age,"岁")
myfunction(name="王小希",age=18)
---
王小希 的年龄为 18 岁
#可以先考虑实参的顺序,然后再通过关键字实参的调用方式
myfunction("王小希",age=18)
---
王小希 的年龄为 18 岁
Notes:
def myfunction(name,age=18):
print(name,"的年龄为",age,"岁")
myfunction("王小希")
myfunction("王小希",age=23)
---
王小希 的年龄为 18 岁
王小希 的年龄为 23 岁
def myfunction1(*names,age=18):
for name in names:
print(name,"的年龄为",age,"岁")
myfunction1("王小希","王小明","罗小黑")
---
王小希 的年龄为 18 岁
王小明 的年龄为 18 岁
罗小黑 的年龄为 18 岁
def myfunction3(**options):
print(type(options))
for key in options:
print(options[key])
dict={'key1':"json1",'key2':"json2"}
print(type(dict))
'''法1:传入 参数名 = value'''
myfunction3(key1="json",key2="json2")
'''法2:直接传入字典,但是记得字典前要加**'''
myfunction3(**dict)
Notes:
函数会创建一个空元组/空字典,接受任意数量的参数值
python可以通过使用"*“,也可以使用**”**“实现接受任意值多个形参**
def myfunction2():
name1 = "王小希",
name2 = ("王小明","罗小黑")
return name1,name2
name1,name2 = myfunction2()
print(name1,name2)
---
('王小希',) ('王小明', '罗小黑')
Notes:
参考python限定方法参数类型、返回值类型、变量类型等
经常使用类型
from typing import List
from util.annotation import constraint
from model.basic.trace import Trace
'''
4大约束条件判别:
- 安全间隔约束
- 优先级约束
- 落地时段约束
- 起飞时段约束
'''
@constraint(value="Constraint1")
# 单一安全间隔约束
def aqjg_constraint(trace1: Trace, trace2: Trace, hjbm_2_index_dict: dict, aqjg_matrix: List[List]) -> bool:
# 航线1先起飞,航线2后起飞
row = hjbm_2_index_dict[trace1.hjbm]
col = hjbm_2_index_dict[trace2.hjbm]
if (abs(trace2.qf_time - trace1.qf_time) < aqjg_matrix[row][col]):
return False
return True
Note:
python限定方法参数类型可以减少方法注释,但是python并不会检查参数类型是否符合,如果参数类型为List[List]二维数组,List一维数组照样可以传进去
下面代码的核心部分包括:
会员类在继承人类时:类后加括号表继承,即class Member (People):
子类(会员类)在初始化对象时,要调用父类(人类)的初始化方法,即
def __init__(self, name, location, career, hope):
super().__init__(name, location, career)
self.hope = hope
类中的方法需要显式传入self
,表明该方法是类对象的行为,这是方法和函数的区别。
子类可以重写父类的方法。
class People:
"""定义人类"""
def __init__(self, name, location, career):
self.name = name
self.location = location
self.career = career
self.age = 18 # 默认的属性值,不需要在init方法列表体现
def introduce_you(self):
# format()方法的另外一个用法,构造消息。也可以把消息写在一个函数里面,有兴趣的圈友可以试一下
introduce = ' Python 实战圈的圈友们好,我是{n},今年{a},来自{l}.我的工作是{c},很高兴认识大家!'
mess = introduce.format(n=self.name,
l=self.location,
a=self.age,
c=self.career)
print(mess)
def read_age(self):
# 读取年龄属性
print('{}今年{}岁'.format(self.name, self.age))
def update_age(self, new_age):
# 更新属性的方法
if new_age < 0:
print('年龄不能为负数')
else:
self.age = new_age
"""
定义会员类,继承类父类People
会员类,有自己的属性introduction
"""
class Member (People):
"""会员类,继承人类"""
def __init__(self, name, location, career, hope):
super().__init__(name, location, career)
self.hope = hope
def introduce_you(self):
""" 重写父类的方法"""
introduce = ' Python 实战圈的圈友们好,我是{n},今年{a},来自{l}.我的工作是{c},很高兴认识大家!在咱们圈子里,我希望自己能 {h}.'
mess = introduce.format(n=self.name,
l=self.location,
a=self.age,
c=self.career,
h=self.hope
)
print(mess)
def set_hope(self, hope):
"""定义子类的方法"""
self.hope = hope
print("{}的希望是{}".format(self.name, self.hope))
# 实例化对象
Grace = Member("Grace", "上海", '数据分析师', '彻底学会Python')
# 实现自我介绍
Grace.introduce_you()
# 实现更新年龄
Grace.update_age(19)
# 调用方法更新年龄
Grace.read_age()
# 请修改你的祝福
这里有个疑惑,请看这段代码:
#Define model
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork,self).__init__()
解读参考self参数 - __ init__ ()方法 super(Net, self).init()是什么
但是为什么super()
里要传子类实例,可以不写吗?
它是由一系列按特定顺序排列的元素组成(有序集合),参考python列表的常用操作方法
list = ['小王','小李','小张','小红']
'''A:列表的输出'''
print("列表元素如下1:{}".format(list))
---
列表元素如下1:['小王', '小李', '小张', '小红']
print(f"列表元素如下2:{list}")
---
列表元素如下2:['小王', '小李', '小张', '小红']
'''列表循环输出'''
for i in List:
print i,
'''B:列表的访问'''
print(list[0])
---
小王
print(list[-1])
---
小红
'''C:列表的插入'''
'''按索引位置插入'''
list.insert(0,'小表弟')
print(f"新列表元素如下3:{list}")
---
新列表元素如下3:['小表弟', '小王', '小李', '小张', '小红']
'''末尾追加(在构建空列表,网络爬虫中较为常用)'''
list.append('大表哥')
print(f"新列表元素如下4:{list}")
---
新列表元素如下4:['小表弟', '小王', '小李', '小张', '小红', '大表哥']
'''B:某个位置插入多个元素'''
list1[3:2] = ['小李子1','小李子2']
---
['小表弟', '小王', '小李','小李子1', '小李子2', '小张', '小红']
'''D:列表的修改'''
#按索引位置修改元素
list[2] = '小李子'
print(f"新列表元素如下5:{list}")
---
新列表元素如下5:['小表弟', '小王', '小李子', '小张', '小红', '大表哥']
'''E:列表的删除'''
'''根据位置删除'''
#用del函数
del list[0]
print(f"新列表元素如下6:{list}")
---
新列表元素如下6:['小王', '小李子', '小张', '小红', '大表哥']
#用pop方法(有返回值,且默认删除末尾元素)
a = list.pop()
print(a)
print(f"新列表元素如下6:{list}")
---
新列表元素如下6:['小王', '小李子', '小张', '小红']
b = list.pop(0)
print(b)
print(f"新列表元素如下7:{list}")
---
新列表元素如下7:['小李子', '小张', '小红']
'''根据值删除'''
list.append('小红')
print(f"新列表元素如下8:{list}")
---
新列表元素如下8:['小李子', '小张', '小红', '小红']
#remove只能删除第一个值=xx的元素
list.remove('小红')
print(f"新列表元素如下9:{list}")
---
新列表元素如下9:['小李子', '小张', '小红']
'''F:列表的排序'''
'''1、永久排序'''
list1 = ['p','f','b','a','c','f','g']
list1.sort()
print('升序',list1)
---
升序 ['a', 'b', 'c', 'f', 'f', 'g', 'p']
list1 = ['p','f','b','a','c','f','g']
list1.sort(reverse=True)
print('降序',list1)
---
降序 ['p', 'g', 'f', 'f', 'c', 'b', 'a']
'''2、临时排序'''
list1 = ['p','f','b','a','c','f','g']
list1_1 = sorted(list1)
print(list1_1)
---
['a', 'b', 'c', 'f', 'f', 'g', 'p']
print(list1)
---
['p', 'f', 'b', 'a', 'c', 'f', 'g']
list1 = ['小表弟', '小王', '小李', '小张', '小红', '大表哥']
'''A: 切片概念(默认:start = 0,end = -1,step = 1 表示从左到右的方向'''
a = list1[2:4]
---
['小李', '小张']
b = list1[:4]
---
['小表弟', '小王', '小李', '小张']
c = list1[4:]
---
['小红', '大表哥']
'''获取最后三个元素'''
d = list1[-3:]
---
['小张', '小红', '大表哥']
'''获取偶数位置元素'''
e = list1[::2]
---
['小表弟', '小李', '小红']
'''获取奇数位置元素'''
f = list1[1::2]
---
['小王', '小张', '大表哥']
'''逆序获取元素'''
g = list1[::-1]
---
['大表哥', '小红', '小张', '小李', '小王', '小表弟']
'''C:复制列表:切片复制等价copy(),=赋值等价于引用'''
list2 = list1[:]
list3 = list2
list2.append('小捣蛋')
list1
---
Out[25]: ['小表弟', '小王', '小李', '小李子1', '小李子2', '小张', '小红', '大表哥']
list2
---
Out[26]: ['小表弟', '小王', '小李', '小李子1', '小李子2', '小张', '小红', '大表哥', '小捣蛋']
list3
---
['小表弟', '小王', '小李', '小李子1', '小李子2', '小张', '小红', '大表哥', '小捣蛋']
备注:
list3是list2的引用,list2修改了,list3也会发生修改
'''G:列表的其他操作'''
list1 = ['p','f','b','a','c','f','g']
'''1、复制列表copy()'''
list2 = list1.copy()
print(list2)
# ['p', 'f', 'b', 'a', 'c', 'f', 'g']
'''2、统计列表中某元素个数'''
print('f出现的次数:',list2.count('f'))
# f出现的次数: 2
print('b出现的次数:',list2.count('b'))
# b出现的次数: 1
'''3、找出某一个元素的索引位置:index'''
print('f的索引位置:',list2.index('f'))
'''4、颠倒顺序'''
print("原:",list2)
list2.reverse()
print("反:",list2)
'''列表长度'''
len(list2)
'''list()函数定义列表'''
list4 = list('hello')
---
['h', 'e', 'l', 'l', 'o']
'''列表的拼接(三种方法)'''
list1 = ['a','b','c']
list2 = ['python','is','my','favorite']
'''+法'''
list3 = list1 + list2
---
list3:Out[9]: ['a', 'b', 'c', 'python', 'is', 'my', 'favorite']
'''extend()'''
list1.extend(list2)
---
list1: Out[11]: ['a', 'b', 'c', 'python', 'is', 'my', 'favorite']
'''*法'''
list4 = list2 * 3
---
Out[15]:
['python',
'is',
'my',
'favorite',
'python',
'is',
'my',
'favorite',
'python',
'is',
'my',
'favorite']
比较两种列表拼接:
list1 = ['p', 'y', 't', 'h', 'o', 'n'].extend(['python', 'Java', 'C++'])
print(type(list1))
---
<class 'NoneType'>
list2 = ['p', 'y', 't', 'h', 'o', 'n']
list3 = ['python', 'Java', 'C++']
list2.extend(list3)
print(list2)
---
['p', 'y', 't', 'h', 'o', 'n', 'python', 'Java', 'C++']
Notes:为什么上面第一种方法实现不了列表拼接。
假设1:'[]'一开始不是列表,是在赋值给变量时自动转换成列表的。
假设2:list.extend()
无返回值
print(type(['p', 'y', 't', 'h', 'o', 'n']))
---
<class 'list'>
print(type(['p', 'y', 't', 'h', 'o', 'n'].extend(['python', 'Java', 'C++'])))
---
<class 'NoneType'>
print(type(list(['p', 'y', 't', 'h', 'o', 'n']).extend(['python', 'Java', 'C++'])))
---
<class 'NoneType'>
list3 = ['python', 'Java', 'C++']
print(type(list3))
<class 'list'>
经验证,假设1错误,假设2成立
'''判断元素是否在列表中 in / not in'''
val = '大王' in list1
---
Out[5]: False
val1 = '大王' not in list1
---
Out[6]: True
'''join()方法将序列中的元素以指定的字符连接生成一个新的字符串'''
linked = '-'
linked.join(list1)
---
Out[32]: '小表弟-小王-小李-小李子1-小李子2-小张-小红-大表哥-小捣蛋'
Notes:
元组通常是不能被修改,而列表是可以
'''1、直接使用'''
tup1 = 1,2,3
print("tup1:",type(tup1))
---
tup1: <class 'tuple'>
'''2、用()'''
tup2 = (1,2,3)
print("tup2:",type(tup2))
---
tup2: <class 'tuple'>
tup3 = (1)
print("tup3:",type(tup3))
---
tup3: <class 'int'>
'''3、用,隔开'''
tup4 = (1,)
print("tup4:",type(tup4))
---
tup4: <class 'tuple'>
'''用tuple()函数'''
'''4、字符串转元组'''
print(tuple("python"))
---
('p', 'y', 't', 'h', 'o', 'n')
'''5、列表转元组'''
print(tuple(['python','Java','C++']))
---
('python', 'Java', 'C++')
'''6、元组里包含元组'''
tup5 = ('p', 'y', 't', 'h', 'o', 'n'),('python', 'Java', 'C++')
print(tup5)
---
(('p', 'y', 't', 'h', 'o', 'n'), ('python', 'Java', 'C++'))
tup6 = ('p', 'y', 't', 'h', 'o', 'n') + ('python', 'Java', 'C++')
print(tup6)
---
('p', 'y', 't', 'h', 'o', 'n', 'python', 'Java', 'C++')
Notes:列表的拼接可以用extend
,但是元组拼接没有
'''元组不能修改'''
tup = (1,[1,2,3,4],'str')
tup[2] = 'java'
print(tup)
---
TypeError: 'tuple' object does not support item assignment
'''修改元组里的列表'''
tup = (1,[1,2,3,4],'str')
tup[1].append(5)
print(tup)
---
(1, [1, 2, 3, 4, 5], 'str')
Notes:
元组里的元素一般是不能修改的,但是如果元组里有列表,就可以通过修改该列表间接修改该元组。
del tup
print(tup)
---
NameError: name 'tup' is not defined
tup = ('python','java','C++')
a,b,c = tup
print(a,b,c)
---
python java C++
# 变量的数量必须和元组中对象的数量一样,否则出错。
a,b = tup
print(a,b)
---
ValueError: too many values to unpack (expected 2)
Notes:
变量的数量必须和元组中对象的数量一样,否则出错
'''嵌套元组也可以拆包'''
tup = (1,'python',('java','C++'))
a,b,(c,d) = tup
print(a,b,d)
---
1 python C++
Notes:
’_‘表示占位符,’*'表示剩余元组元素
tup = (1,'python',('java','C++'))
# 如何剔除不想要的变量?
# 使用 _ 表示不想要的元组值
_,_,(a,_) = tup
print(a)
---
java
#使用 * 表示任意多个对象值 *rest
a,*rest = tup
print(a)
print(*rest)
---
1
python ('java', 'C++')
a = 'java'
b = 2
a,b = b,a
print(a,b)
---
2 java
Notes:
Notes:
元组内元素类型一致才能使用max
函数
tup = (1,2,3,4,5,6,[1,2,3,4],'str')
tup1 = (1,2,3,4,5,6)
'''元组其余操作'''
print(max(tup))
---
TypeError: '>' not supported between instances of 'list' and 'int'
print(tup.count(2))
---
1
tup1 = (1,2,3,4,5,6)
'''元组其余操作'''
print(max(tup1))
print(min(tup1))
---
6
1
tup = (1,2,[1,2,3,4],'str')
print(tup.index(3))
---
ValueError: tuple.index(x): x not in tuple
print(tup.index(2))
---
1
跳转到开头
>>> b=[j for i in a for j in i]
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9]
但是要注意一点,假设用列表append值,for写在一行时,有可能会导致传入的值是一个对象,这样在列表遍历时就会报错
>>> payoff_Matrix = list()
>>> print(payoff_Matrix)
>>> print([[0, 0]] * 5)
>>> payoff_Matrix.append([[0, 0]] * 5 for i in range(0, 5))
>>> print(payoff_Matrix)
[]
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[<generator object <genexpr> at 0x000001D00AF0B5C8>]
所以这时候尽量不要写在同一行
>> payoff_Matrix = list()
>> print(payoff_Matrix)
>> print([[0, 0]] * 5)
>> for i in range(0, 2):
>> payoff_Matrix.append([[0, 0]] *2)
>> print(payoff_Matrix)
[]
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
foo = [2,18,6,9,35,44]
print([x for x in foo if x % 3 == 0])
---
[18, 6, 9]
参考https://blog.csdn.net/weixin_43665662/article/details/113437279
t_list = ["apple","banana","key"]
t_dict = {el : index for index, el in enumerate(t_list)} #注意是{},不是[]
print(t_dict)
---
{'apple': 0, 'banana': 1, 'key': 2}
>>> print([0] * 10)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
参考Python 获取字典中最大值及对应的键
prices = {
'A':123,
'B':450.1,
'C':12,
'E':444,
}
max_prices = max(zip(prices.values(), prices.keys()))
print(max_prices) # (450.1, 'B')
如果key=0
不存在,mydict['0']
会报错
d = dict()
# print(d['0']) #KeyError: '0'
print('0' in d)
print(d.get('0'))
---
False
None
python的三目运算符和c++,java的不一样
a=(x if (x>y) else y)
参考Python:用户自定义异常
java用throw,python用raise
def modelLoader(modelName):
'''
可选模型有:GPUHA,DHA,ARHA,RDHA,RHA3
:return: 返回模型
'''
if (modelName == 'GPUHA'): return GPUHA.GPUHA()
elif(modelName == 'DHA'): return DHA.DHA([None], [None])
elif(modelName == 'ARHA'): return ARHA.ARHA()
elif(modelName == 'RDHA'): return RDHA.RDHA([None], [None])
elif(modelName == 'RHA3'): return RHA3.rHA()
else:
raise(modelException(modelName))
model = modelLoader("RHA34")
---
Traceback (most recent call last):
File "E:/python/EGG/main.py", line 63, in <module>
model = modelLoader("RHA34")
File "E:/python/EGG/main.py", line 26, in modelLoader
raise(modelException(modelName))
__main__.modelException: <exception str() failed>
RHA34 does not exist, please correct your modelName
Python多线程之threading.Thread实现
from threading import Thread
class MyThread(Thread):
def run(self):
function_name(self.parameter1)
def __init__(self, parameter1):
Thread.__init__(self)
self.parameter1 = parameter1
t = MyThread(parameter1)
t.start()
# 只需要增加一句代码:子线程执行完毕以后,主线程再关闭
t.join()
同步锁:RLock
threading.RLock()
lock.acquire() # 加锁
lock.release() # 释放锁
---
Note:RLock和Condition用途不同
条件变量:cond
Python 线程条件(Condition),(线程等待另一个线程的执行)
import threading
import time
def go1():
with cond: #使用条件变量(资源 Lock)
for i in range(8):
time.sleep(1)
print(threading.current_thread().name,i,"go11")
if i==5:
cond.wait() #等待cond.notify(),再继续执行。(释放条件变量(资源 Lock))
def go2():
with cond: #使用条件变量(资源 Lock)
for i in range(7):
time.sleep(1)
print(threading.current_thread().name, i)
cond.notify() #通知,触发 cond.wait()。(释放条件变量(资源 Lock))
cond=threading.Condition() #线程条件变量
threading.Thread(target=go1).start() #和下面的线程的次序不能调。这个线程先拿到cond条件变量(资源 Lock)
threading.Thread(target=go2).start() #这个线程不会先拿到cond条件变量(资源 Lock)
事件管理标志:event
参考Python threading中event的使用
通过threading.Event()可以创建一个事件管理标志,该标志(event)默认为False,event对象主要有四种方法可以调用:
event.wait(timeout=None)
:调用该方法的线程会被阻塞,如果设置了timeout参数,超时后,线程会停止阻塞继续执行;event.set()
:将event的标志设置为True,调用wait方法的所有线程将被唤醒;event.clear()
:将event的标志设置为False,调用wait方法的所有线程将被阻塞;event.isSet()
:判断event的标志是否为True。可以开启一个线程去修改这个标志位(不用加锁),进而去关闭所有正在运行的线程(对于while(True)线程的关闭很管用)。
def setCond(lock,event):
for i in range(0,10):
time.sleep(5)
#lock.acquire()
event.set() #将event的标志设置为True
#lock.release()
while(True):
flag = event.isSet()
if(flag):
break
参考
python 线程安全的数据类型_详解python多线程、锁、event事件机制的简单使用
python线程池的使用 必看,很详细!!!!!
Python多线程-Event(事件对象)
a、创建线程池ThreadPoolExecutor,提交任务submit(),查询状态done(),获取结果result()
from concurrent.futures import ThreadPoolExecutor,as_completed
b、取消任务cancel()
使用cancel()方法可以取消提交的任务,如果任务已经在线程池中运行了,就取消不了。上面的例子,线程池大小为1,添加两个线程后,第一个线程已经在线程池运行,取消不了,第二个线程还在等待,所以可以取消
c、as_completed() as_completed()方法是一个生成器,在没有任务完成的时候,会阻塞
d、使用map方法,无需提前使用submit方法,map方法与python标准库中的map含义相同,都是将序列中的每个元素都执行同一个函数
for data in executor.map(get_html, time_list):
print(data)
e、shutdown():关闭executor
在用完一个线程池后,应该调用线程池的shutdown()方法,该方法将启动线程池的关闭序列。调用shutdown()方法后的线程池不再接受新任务,但会将以前所有已提交的任务执行完成。当线程池中的所有任务都执行完后,该线程池中的所有线程都会死亡。
参考
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
def run_proc(name):
time.sleep(10)
print('run_proc')
print('Run child process %s (%s)...' % (name, os.getpid()))
def hello_world():
# time.sleep(5)
time.sleep(20)
print('hello world!')
print('Run child process (%s)...' % (os.getpid()))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p1 = Process(target=run_proc, args=('test',))
p2 = Process(target=hello_world)
print('Process will start.')
p1.start()
p2.start()
print('Process end.')
---
Parent process 14368.
Process will start.
Process end.
run_proc
Run child process test (11368)...
hello world!
Run child process (16428)...
为了同步主进程和子进程,这时就需要用到p1.join()
,目的是让主进程阻塞,等待子进程结束后再继续往下运行。
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
def run_proc(name):
time.sleep(10)
print('run_proc')
print('Run child process %s (%s)...' % (name, os.getpid()))
def hello_world():
# time.sleep(5)
time.sleep(20)
print('hello world!')
print('Run child process (%s)...' % (os.getpid()))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p1 = Process(target=run_proc, args=('test',))
p2 = Process(target=hello_world)
print('Process will start.')
p1.start()
p2.start()
p1.join()
p2.join()
print('Process end.')
---
Parent process 9892.
Process will start.
run_proc
Run child process test (17152)...
hello world!
Run child process (8816)...
Process end.
可以通过queue.get()
来获取不同进程处理的值
参考
import multiprocessing as mp
def job(q,a):
res=0
for i in range(20):
res+=i
q.put(res+a)#queue #将返回值存入queue中
if __name__=='__main__':
q=mp.Queue() #在进程开始前定义Queue(先进先出),可以在访问冲突时自动对Queue加锁(进程安全)
p1=mp.Process(target=job,args=(q,1)) #注意参数是元组,即使只有一个参数,也要写成(q,)的tuple
p2=mp.Process(target=job,args=(q,2))
p1.start()
p2.start()
p1.join()
p2.join()
res1=q.get()
res2=q.get()
print(res1) #逐个取出
print(res2)
print(res1+res2)
---
191
192
383
参考python多进程下的生产者和消费者模型
from multiprocessing import Process, Queue
import time
# 消费者方法
def consumer(q, name):
while True:
res = q.get()
# if res is None: break
print(f"{name} 吃了 {res[0]} 个 {res[1]}")
# 生产者方法
def producer(q, name, food):
while(True):
time.sleep(1) # 模拟生产西瓜的时间延迟
res = (1,food)
print(f"{name} 生产了 1 个 {food}")
# 把生产的vegetable放入到队列中
q.put(res)
if __name__ == "__main__":
# 创建队列
q = Queue()
# 创建生产者
p1 = Process(target=producer, args=(q, "kelly", "西瓜"))
c1 = Process(target=consumer, args=(q, "peter",))
p1.start()
c1.start()
# p1.join()
# q.put(None)
print("主进程")
---
主进程
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
kelly 生产了 1 个 西瓜
peter 吃了 1 个 西瓜
...
如果将视频帧frame放入队列,也可以看成是生产者消费者问题
from multiprocessing import Process,Queue
import cv2
import time
cam = cv2.VideoCapture(0)
#开启子进程生成视频帧
def generate_frame(q):
while(True):
success, frame = cam.read()
if(success):
q.put(frame)
#开启子进程读取视频帧
def read_frame(q) -> None: # 提醒返回值是一个None
#开始逐帧读取
while(True):
frame = q.get()
print(frame)
cv2.imshow("res",frame)
c = cv2.waitKey(5) #设置一下延迟(即每一帧的停留时间),否则不能正常显示图片
if(c == 27):
break
if __name__ == '__main__':
# queue_t = queue.Queue()
queue_t = Queue()
print("queue是否为空 : ",queue_t.empty())
flag = True
p1 = Process(target=generate_frame, args=(queue_t,))
p2 = Process(target=read_frame, args=(queue_t,))
p1.start()
p2.start()
p1.join() #阻塞主进程
p2.join() #阻塞主进程
print("End")
Python 队列(Queue)用法
python全局变量的线程安全问题
Python并行编程cookbook(含mpi4py,Lock,Celery,Queue)
from Queue import Queue,LifoQueue,PriorityQueue
#先进先出队列
q=Queue(maxsize=5)
#后进先出队列
lq=LifoQueue(maxsize=6)
#优先级队列
pq=PriorityQueue(maxsize=5)
for i in range(5):
q.put(i)
lq.put(i)
pq.put(i)
print "先进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(q.queue,q.empty(),q.qsize(),q.full())
print "后进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(lq.queue,lq.empty(),lq.qsize(),lq.full())
print "优先级队列:%s;是否为空:%s,多大,%s;是否满,%s" %(pq.queue,pq.empty(),pq.qsize(),pq.full())
print q.get(),lq.get(),pq.get()
print "先进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(q.queue,q.empty(),q.qsize(),q.full())
print "后进先出队列:%s;是否为空:%s;多大,%s;是否满,%s" %(lq.queue,lq.empty(),lq.qsize(),lq.full())
print "优先级队列:%s;是否为空:%s,多大,%s;是否满,%s" %(pq.queue,pq.empty(),pq.qsize(),pq.full())
在Python中,队列是最常用的线程间的通信方法,因为它是线程安全的,自带锁。而Condition等需要额外加锁的代码操作,在编程对死锁现象要很小心,Queue就不用担心这个问题。
#from Queue import Queue
from queue import Queue
import time,threading
q=Queue(maxsize=0)
def product(name):
count=1
while True:
q.put('气球兵{}'.format(count))
print ('{}训练气球兵{}只'.format(name,count))
count+=1
time.sleep(5)
def consume(name):
while True:
print ('{}使用了{}'.format(name,q.get()))
time.sleep(1)
q.task_done()
t1=threading.Thread(target=product,args=('wpp',))
t2=threading.Thread(target=consume,args=('ypp',))
t3=threading.Thread(target=consume,args=('others',))
t1.start()
t2.start()
t3.start()
Note:
Queue
模块,直接import queue
即可python中multiprocessing.pool
的使用参考
Note:
常见命令有:apply
,apply_async
,join
,close
,terminate
torch.multiprocessing.Pool
的使用基本一致
#coding: utf-8
from torch.multiprocessing import Pool
import time
def func(msg):
while(True):
print("msg:", msg)
time.sleep(3)
print("end")
class MyProcess:
#线程池交给类方法去处理
def test(self):
pool = Pool(processes=3)
for i in range(4):
msg = "hello %d" % (i)
pool.apply_async(func, (msg,)) # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
time.sleep(5)
print("Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~")
pool.close()
pool.terminate() # 中断所有工作进程
pool.join() # 调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print("Sub-process(es) done.")
if __name__ == "__main__":
process = MyProcess()
process.test()
---
msg: hello 0
msg: hello 1
msg: hello 2
end
msg: hello 0
end
msg: hello 1
end
msg: hello 2
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
Sub-process(es) done.
如果修改成这样:
...
def test(self):
pool = Pool(processes=3)
for i in range(4):
msg = "hello %d" % (i)
t = pool.apply_async(func, (msg,)) # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
t.get() #会反复调用进程1,等待其结果的返回,直到有结果返回
...
---
msg: hello 0
end
msg: hello 0
end
msg: hello 0
end
msg: hello 0
end
msg: hello 0
end
msg: hello 0
如果有返回值,则效果如下:
def func(msg):
while(True):
print("msg:", msg)
time.sleep(3)
print("end")
return "ttttt" + str(msg)
...
def test(self):
pool = Pool(processes=3)
for i in range(4):
msg = "hello %d" % (i)
t = pool.apply_async(func, (msg,)) # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
res = t.get() #会反复调用进程1,等待其结果的返回
print(res) #一旦取到结果,则不再反复调用
...
---
msg: hello 0
end
ttttthello 0
msg: hello 1
end
ttttthello 1
msg: hello 2
end
ttttthello 2
msg: hello 3
end
ttttthello 3
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
Sub-process(es) done.
Flask中使用进程池参考 在Flask服务中使用进程池加速
import flask
import math
import json
from concurrent.futures import ProcessPoolExecutor
process_pool = ProcessPoolExecutor()
app = flask.Flask(__name__)
# 判断是否是素数
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
@app.route("/is_prime/" )
def api_is_prime(numbers):
number_list = [int(x) for x in numbers.split(",")]
rsts = process_pool.map(is_prime, number_list)
rst = json.dumps(
dict(zip(number_list, rsts))
)
return rst
if __name__ == '__main__':
app.run()
主要原因是该进程往同步队列里丢数据,导致进程池无法被执行,去掉同步队列的代码即可。
解决方案:
将原来创建Queue的方式,由multiprocessing.Queue()
改成multiprocessing.Manager.Queue()
即可,参考Python3之无法在进程池中使用队列Queue的解决方案
import multiprocessing
import time
class Test:
def __init__(self):
self.pool = multiprocessing.Pool()
# self.queue = multiprocessing.Queue()
m = multiprocessing.Manager()
self.queue = m.Queue()
...
还需要将原来用mp
创建的共享数据,转换成用mp.Manager()
来创建(比如Event,Value,Queue)
import multiprocessing as mp
...
manager = mp.Manager()
e = manager.Event()
queues = [manager.Queue() for _ in range(self.args.num_cams)]
queues_res = [manager.Queue() for _ in range(self.args.num_cams)] #存储最终结果的队列
counter1 = manager.Value('i', 0)
counter2 = manager.Value('i', 0)
argss = [copy.deepcopy(self.args) for _ in range(self.args.num_cams)]
# if self.args.num_cams == 1:
if self.args.video is None:
argss[0].video = video
pool.apply_async(extract_keypoints_parallel, (queues[0], argss[0], counter1, counter2, self.consecutive_frames, e))
pool.apply_async(alg2_sequential, (queues, argss, self.consecutive_frames, e, queues_res))
...
在帮师姐将fall_detection代码嵌入到检测平台中发现,fall_detection是多进程的,而且其中一个进程负责输出fall的检测帧结果。要想让主进程从子进程中取出frame,只能通过两个子进程的queues来获取,这里为了图方便,直接塞进一个新的queues_res来装入frame,交给主进程去读取。但是为了避免两个子进程不被服务器管理,这里引入了进程池,但是在使用时遇到了一些问题。
原始代码如下所示,运行会报如下错误raise convert_to_error(kind, result) multiprocessing.managers.RemoteError:
,主要原因是主进程使用了子进程的共享队列queues_res,虽然manager.Queue()
是进程安全的,但是这进程安全是针对进程池提供的进程而言的,对于主进程,它不被Pool管理,故使用queues_res时,没有加锁,会报错。
class A(object):
...
def begin(self,pool,video):
print('Starting...')
manager = mp.Manager()
e = manager.Event()
queues = [manager.Queue() for _ in range(self.args.num_cams)]
queues_res = [manager.Queue() for _ in range(self.args.num_cams)] #存储最终结果的队列
counter1 = manager.Value('i', 0)
counter2 = manager.Value('i', 0)
argss = [copy.deepcopy(self.args) for _ in range(self.args.num_cams)]
# if self.args.num_cams == 1:
if self.args.video is None:
argss[0].video = video
p1 = pool.apply_async(extract_keypoints_parallel,
(queues[0], argss[0], counter1, counter2, self.consecutive_frames, e))
# pool.apply_async(alg2_sequential, (queues, argss, self.consecutive_frames, e, queues_res))
p2 = pool.apply_async(alg2_sequential, (queues, argss, self.consecutive_frames, e, queues_res))
return queues_res
if __name__ == "__main__":
#输入接口
f = FallDetector()
pool = Pool(processes=3)
# pool = Pool(processes=3) # 用进程池管理多个进程
# queues_res = f.begin(video="rtsp://admin:[email protected]:554/h264/ch1/main/av_stream")
# queues_res = f.begin(pool=pool,video=0)
queues_res = f.begin(pool,video=0)
f.begin(pool, video=0)
print("输出结果")
for frame in detect(queues_res):
print(frame)
# print(frame['img'])
# cv2.imshow("res",frame['img'])
cv2.imshow("res", frame)
c = cv2.waitKey(5)
if (c == 27):
break
pool.terminate() #终止进程池所有工作进程
---
Process SpawnPoolWorker-2:
Process SpawnPoolWorker-1:
Traceback (most recent call last):
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\process.py", line 258, in _bootstrap
self.run()
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\pool.py", line 108, in worker
task = get()
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\queues.py", line 337, in get
return _ForkingPickler.loads(res)
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\managers.py", line 881, in RebuildProxy
return func(token, serializer, incref=incref, **kwds)
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\managers.py", line 930, in AutoProxy
incref=incref)
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\managers.py", line 731, in __init__
self._incref()
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\managers.py", line 786, in _incref
dispatch(conn, None, 'incref', (self._id,))
File "D:\programmingSoftware\Anaconda\Anaconda\lib\multiprocessing\managers.py", line 82, in dispatch
raise convert_to_error(kind, result)
multiprocessing.managers.RemoteError:
解决思路:主进程在使用queue_res时,加锁即可。参考Why python throws “multiprocessing.managers.RemoteError” for shared lock?
对同一个操作效果,比较时间开销
发现类对象调用类内所有方法,和类对象调用类内汇总方法,时间开销差不多
import time
class A:
def __init__(self):
print("init")
def func1(self):
for i in range(0,10000):
# print("func1")
continue
pass
def func2(self):
for i in range(0, 10000):
# print("func2")
continue
pass
def func3(self):
for i in range(0, 10000):
# print("func3")
continue
pass
def all(self):
self.func1()
self.func2()
self.func3()
'''类外对象调用类内func1,func2,func3方法'''
a = A()
startT = time.time()
a.func1()
a.func2()
a.func3()
endT = time.time()
print("interval(func1,func2,func3) = ",endT - startT)
'''类外对象调用类内all方法,实现对所有方法func1,func2,func3的调用'''
b = A()
startT = time.time()
b.all()
endT = time.time()
print("interval(all) = ",endT - startT)
---
init
interval(func1,func2,func3) = 0.0009984970092773438
init
interval(all) = 0.0009984970092773438
比较类对象在管理数据流和不管理数据流情况下的时间开销,发现类对象管理数据流比不管理数据流慢,小则几毫秒,大则2秒,但是感觉还是有点问题,要不试试分别运行这两段代码??接着就有了实验3。
import time
import cv2
class A:
def __init__(self,videoPath=None):
print("init")
self.videoPath = videoPath
def func1(self):
k = 0
video = cv2.VideoCapture(self.videoPath)
totalFrame = video.get(cv2.CAP_PROP_FRAME_COUNT)
print("totalFrame = ", totalFrame)
while(k < totalFrame):
ret,img = video.read()
self.func4()
self.func5()
cv2.imshow("img",img)
cv2.waitKey(1)
k += 1
continue
video.release()
print()
def func2(self):
for i in range(1000):
continue
pass
def func3(self):
for i in range(1000):
continue
pass
def func4(self):
for i in range(1000):
continue
pass
def func5(self):
for i in range(1000):
continue
pass
def all(self):
self.func1()
self.func2()
self.func3()
videoPath = "E:/python/数据集/YawDD数据集/YawDD/YawDD dataset/Dash/Female/9-FemaleNoGlasses.avi"
'''类对象不管理数据流'''
a = A()
startT = time.time()
video = cv2.VideoCapture(videoPath)
k = 0
totalFrame = video.get(cv2.CAP_PROP_FRAME_COUNT)
print("totalFrame = ",totalFrame)
while(k < totalFrame): #video.isOpened()检查初始化是否成功
ret,img = video.read()
# a.func1()
a.func2()
a.func3()
k += 1
cv2.imshow("img", img)
cv2.waitKey(1)
continue
video.release()
endT = time.time()
video.release()
print()
print("interval(without source governing) = ",endT - startT)
'''类对象本身管理数据流'''
b = A(videoPath=videoPath)
startT = time.time()
b.all()
endT = time.time()
print("interval(with source governing) = ",endT - startT)
---
init
totalFrame = 1532.0
interval(without source governing) = 18.046899795532227
init
totalFrame = 1532.0
interval(with source governing) = 20.535900115966797
---
init
totalFrame = 1532.0
interval(without source governing) = 16.4721097946167
init
totalFrame = 1532.0
interval(with source governing) = 18.723338842391968
怀疑时间差产生的原因是前面一段代码运行时python没有及时释放内存,或者没有释放某些子程序,导致CPU负载大。因此分别运行实验2这两段代码,得出的结论是类对象管理数据流和不管理数据流,两者运行时间开销差不多
init
totalFrame = 1532.0
interval(without source governing) = 13.777432680130005
init
totalFrame = 1532.0
interval(with source governing) = 12.208465337753296
参考面向对象与面向过程的优缺点
1、面向对象相对面向过程的优点
1)结构清晰。使人们的编程与实际的世界更加接近,所有的对象被赋予属性和方法,结果编程就更加富有人性化。
2)封装性。减小外部对内部的影响。封装将对象有关的数据和行为封装成整体来处理,使得对象以外的部分不能随意存取对象的内部属性,从而有效地避免了外部错误对它的影响,大大减小了查错和排错的难度。
3)容易扩展,代码重用率高。容易扩展,在大框架不变的情况下很容易就开发出适合自己的功能,实现简单,可有效地减少程序的维护工作量,软件开发效率高。
2、面向对象相对面向过程的缺点
1)增加工作量。如果一味地强调封装,当进行修改对象内部时,对象的任何属性都不允许外部直接存取,则要增加许多没有其他意义、只负责读或写的行为。这会为编程工作增加负担,增加运行开销,并且使程序显得臃肿。
2)性能低。由于面向更高的逻辑抽象层,使得面向对象在实现的时候,不得不做出性能上面的牺牲,计算时间和空间存储大小的都开销很大。
参考用好Assert断言,让Bug无藏身之地~
self.assertTrue()
是unittest
自带的断言方法
import unittest
class MyClass(unittest.TestCase):
def test_vertification(self):
self.assertTrue(1 == 2) #unittest自带的断言方法,会报AssertionError: False is not true
def test_vertification1(self):
# assert(1 == 2) #会报 assert(1 == 2) AssertionError
assert(1 == 1)
__import__
的区别(python反射)参考
__import__
与import的区别__import__
与import的对比
import | __import__ |
|
---|---|---|
倾向 | 固定式声明 | 动态加载 |
适用场景 | 已经明确知道项目中哪些模块 | 模块可以动态插拔、动态引入运行 |
举例 | import os #导入固有的os模块 | __import__ (‘employee’).find(name=‘李林’) #动态加载刚安装的员工管理模块,并且查找一个叫“李林”的人 |
语句 from spam.ham import eggs, sausage as saus
的结果将为
_temp = __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], 0)
eggs = _temp.eggs
saus = _temp.sausage
__import__
,__getattr__
)参考
#dynamic.py
imp = input("请输入模块:")
dd = __import__(imp) # 等价于import imp
inp_func = input("请输入要执行的函数名称:")
f = getattr(dd,inp_func,None)#作用:从导入模块中找到需要调用的函数inp_func,然后返回一个该函数的引用.没有找到就返回None
f() # 执行该函数
Note:
>>testInflection.model.A
def helloTest():
print("test")
pass
>>testInflection.model.B
def helloTest():
print("test")
pass
>>test.py
_temp = __import__("testInflection.model",globals(),locals(),["A","B"])
A = _temp.A
A1 = getattr(_temp,"A") #获取模块的python文件
func = getattr(A,"helloTest") #获取python文件中的"helloTest"方法
print("A = {}, A1 = {}, A.func = {}".format(A,A1,func)) #A和A1等价
---
A = <module 'testInflection.model.A' from 'E:\\研究生任务\\python算子实现\\wangxiaoxi1\\src\\testInflection\\model\\A.py'>, A1 = <module 'testInflection.model.A' from 'E:\\研究生任务\\python算子实现\\wangxiaoxi1\\src\\testInflection\\model\\A.py'>, A.func = <function helloTest at 0x0000029B2E2C6598>
Note:
__import__
导入的是模块名(module)(注意路径要写对,格式为A.B
,引入的是模块名,不是模块中的python文件,python文件要在__import__
中额外指定fromlist=()。)getattr()
获取模块中的python文件,以及python文件里的类或方法。__import__
作用和importlib.import_module()
类似。例如
module = __import__("model",globals(),locals(),[modelName]) #获取模块
pyModel = getattr(module,modelName) #获取模块中python文件
modelCls = getattr(pyModel,modelName)() #获取类模型,并实例化
model = modelCls()
python中时间、日期、时间戳的转换
# 引入模块
import time, datetime
# [python中时间、日期、时间戳的转换](https://www.cnblogs.com/jfl-xx/p/8024596.html)
# 字符类型的时间
tss1 = '2013-10-10 23:40:00'
# 转为时间数组
timeArray = time.strptime(tss1, "%Y-%m-%d %H:%M:%S")
print(timeArray)
# timeArray可以调用tm_year等
print(timeArray.tm_year) # 2013
# 转为时间戳
timeStamp = int(time.mktime(timeArray))
print(timeStamp) # 1381419600
tss2 = "2013-10-10 23:40:00"
# 转为数组
timeArray = time.strptime(tss2, "%Y-%m-%d %H:%M:%S")
# 转为其它显示格式
otherStyleTime = time.strftime("%Y/%m/%d %H:%M:%S", timeArray)
print(otherStyleTime) # 2013/10/10 23:40:00
tss3 = "2013/10/10 23:40:00"
timeArray = time.strptime(tss3, "%Y/%m/%d %H:%M:%S")
otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
print(otherStyleTime) # 2013-10-10 23:40:00
Note:
解决OverflowError: mktime argument out of range
原因:时间戳是从1970年1月1日早上8点开始的,于是将开始时的代码修改如下即可正常运行
begin = time.mktime(time.strptime('1970-01-01 08:00:00', '%Y-%m-%d %H:%M:%S'))
windows下才会出现这个问题。
def func():
pass
class A():
pass
func_a = func()
class_A = A()
if func_a:
print(f"func_a {True}")
else:
print(f"func_a {False}")
if class_A :
print(f"class_A {True}")
else:
print(f"class_A {True}")
---
func_a False
class_A True
g = lambda x : x * 2 #参数 : 返回值
res1 = g(2)
print(res1) #4
res2 = g(3)
print(res2) #6
lambda作为一个表达式,定义了一个匿名函数,上例的代码x为入口参数,x*2为函数体,用函数来表示为:
1 def g(x):
2 return x * 2
相较于函数的形式,lambda表达式更为简洁
lambda表达式接受列表[]
类型的输入
import numpy as np
f = lambda x : x * 2
state = np.random.RandomState(2)
x_all = state.permutation(5)
y_all = f(x_all)
print(f"x_all = {x_all}")
print(f"y_all = {y_all}")
---
x_all = [2 4 1 3 0]
y_all = [4 8 2 6 0]
这里使用torch进行one-hot编码
import torch
f = lambda y: torch.zeros(10,dtype=torch.float).scatter_(dim=0,index=torch.tensor(y),value=1)
res = f(1)
print(res)
---
tensor([0., 1., 0., 0., 0., 0., 0., 0., 0., 0.])
参考Python lambda介绍
Python中,也有几个定义好的全局函数方便使用的,filter, map, reduce
foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
print filter(lambda x: x % 3 == 0, foo) #等价于:if(x % 3 == 0) return x
#[18, 9, 24, 12, 27]
print map(lambda x: x * 2 + 10, foo) #等价于: for + return x * 2 + 10
#[14, 46, 28, 54, 44, 58, 26, 34, 64]
print reduce(lambda x, y: x + y, foo) #等价于:两两相加,做规约
#139
上面例子中的map的作用,非常简单清晰。但是,Python是否非要使用lambda才能做到这样的简洁程度呢?在对象遍历处理方面,其实Python的for…in…if语法已经很强大,并且在易读上胜过了lambda。
比如上面map的例子,可以写成:
print [x * 2 + 10 for x in foo]
非常的简洁,易懂。
filter的例子可以写成:
print [x for x in foo if x %3 ==0]
同样也是比lambda的方式更容易理解。
lambda使用说明:
lambda 定义了一个匿名函数
lambda 并不会带来程序运行效率的提高,只会使代码更简洁。
如果可以使用for…in…if来完成的,坚决不用lambda。
如果使用lambda,lambda内不要包含循环,如果有,我宁愿定义函数来完成,使代码获得可重用性和更好的可读性。
参考https://blog.csdn.net/qq_38890412/article/details/101721571
class Student:
def __init__(self, name, subject, mark):
self.name = name
self.subject = subject
self.mark = mark
s1 = Student("Jack", "os", 60)
s2 = Student("Jim", "cn", 61)
s3 = Student("Pony", "se", 65)
#方法1:lambda表达式
print(f"lambda expression")
L = [s1, s2, s3]
L.sort(key=lambda t: t.mark) #传入一个函数,按分数从小到大排序学生
for i in range(0, len(L)):
print(L[i].name + "," + L[i].subject + "," + str(L[i].mark))
---
lambda expression
Jack,os,60
Jim,cn,61
Pony,se,65
等价于:
L = [s1, s2, s3]
def key(t):
return t.mark
L.sort(key=key) #传入一个函数,按分数从小到大排序学生
for i in range(0, len(L)):
print(L[i].name + "," + L[i].subject + "," + str(L[i].mark))
参考
这种方式最简单,在循环里面放入要执行的任务,然后 sleep 一段时间再执行
from datetime import datetime
import time
# 每n秒执行一次
def timer(n):
while True:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
time.sleep(n)
# 5s
timer(5)
这个方法的缺点是,只能执行固定间隔时间的任务,如果有定时任务就无法完成,比如早上六点半喊我起床。并且 sleep 是一个阻塞函数,也就是说 sleep 这一段时间,啥都不能做。
threading 模块中的 Timer 是一个非阻塞函数,比 sleep 稍好一点。
from datetime import datetime
from threading import Timer
# 打印时间函数
def printTime(inc):
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
t = Timer(inc, printTime, (inc,))
t.start()
# 5s
printTime(5)
Timer 函数第一个参数是时间间隔(单位是秒),第二个参数是要调用的函数名,第三个参数是调用函数的参数(tuple)
终于找到了可以每天定时喊我起床的方式了
APScheduler是一个 Python 定时任务框架,使用起来十分方便。提供了基于日期、固定时间间隔以及 crontab 类型的任务,并且可以持久化任务、并以 daemon 方式运行应用。
使用 APScheduler 需要安装
pip install apscheduler
首先来看一个周一到周五每天早上6点半喊我起床的例子
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
# 输出时间
def job():
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
# BlockingScheduler
scheduler = BlockingScheduler()
scheduler.add_job(job, 'cron', day_of_week='1-5', hour=6, minute=30)
scheduler.start()
APScheduler四个组件
APScheduler 四个组件分别为:触发器(trigger),作业存储(job store),执行器(executor),调度器(scheduler)。
a、触发器(trigger)
包含调度逻辑,每一个作业有它自己的触发器,用于决定接下来哪一个作业会运行。除了他们自己初始配置意外,触发器完全是无状态的
APScheduler 有三种内建的 trigger:
date: 特定的时间点触发
interval: 固定时间间隔触发
cron: 在特定时间周期性地触发
b、作业存储(job store)
存储被调度的作业,默认的作业存储是简单地把作业保存在内存中,其他的作业存储是将作业保存在数据库中。一个作业的数据讲在保存在持久化作业存储时被序列化,并在加载时被反序列化。调度器不能分享同一个作业存储。
APScheduler 默认使用 MemoryJobStore,可以修改使用 DB 存储方案
c、执行器(executor)
处理作业的运行,他们通常通过在作业中提交制定的可调用对象到一个线程或者进城池来进行。当作业完成时,执行器将会通知调度器。
最常用的 executor 有两种:
ProcessPoolExecutor
ThreadPoolExecutor
d、调度器(scheduler)
通常在应用中只有一个调度器,应用的开发者通常不会直接处理作业存储、调度器和触发器,相反,调度器提供了处理这些的合适的接口。配置作业存储和执行器可以在调度器中完成,例如添加、修改和移除作业。
配置调度器(★★★★★)
APScheduler提供了许多不同的方式来配置调度器,你可以使用一个配置字典或者作为参数关键字的方式传入。你也可以先创建调度器,再配置和添加作业,这样你可以在不同的环境中得到更大的灵活性。
下面来看一个简单的 BlockingScheduler
例子
from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime
def job():
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
# 定义BlockingScheduler
sched = BlockingScheduler()
sched.add_job(job, 'interval', seconds=5)
sched.start()
上述代码创建了一个 BlockingScheduler
,并使用默认内存存储和默认执行器。(默认选项分别是 MemoryJobStore
和 ThreadPoolExecutor
,其中线程池的最大线程数为10)。配置完成后使用 start()
方法来启动。
如果要给job传参,可以在add_job
中使用args
参数,如果要给job设置指定id,可以使用id
参数
rom datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
def func(name):
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now + f" Hello world, {name}")
scheduler = BlockingScheduler()
scheduler.add_job(func, 'interval', seconds=3, args=["desire"], id="func")
scheduler.start()
移除job:
remove_job
方法add_job()
中得到的job实例调用remove()
方法如果job_id
不存在,remove_job
会报错,可以用try - except来处理
# remove
job = scheduler.add_job(func, 'interval', seconds=3, args=["desire"], id="job_remove")
job.remove()
# remove_job
scheduler.add_job(func, 'interval', seconds=3, args=["desire"], id="job_remove")
scheduler.remove_job(job_id="job_remove")
终止调度器中的执行器:
scheduler.shutdown() #终止调度器中的任务存储器以及执行器
scheduler.shutdown(wait=False)
默认情况,会终止任务存储器以及执行器,然后等待所有目前执行的job完成后(自动终止),wait=False
此参数不会等待任何运行中的任务完成,直接终止。但是如果scheduler没有执行,shutdown()
会报错:
参考
with表达式其实是try-finally的简写形式。但是又不是全相同。
实际上,在with后面的代码块抛出异常时,exit()方法被执行。开发库时,清理资源,关闭文件等操作,都可以放在exit()方法中。
with open('1.txt') as f:
print(f.read())
print(f.closed)
with 语句实质是上下文管理:
class Mycontex(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print("进入enter")
return self
def do_self(self):
print(self.name)
def __exit__(self,exc_type,exc_value,traceback):
print("退出exit")
print(exc_type,exc_value)
if __name__ == '__main__':
with Mycontex('test') as mc:
mc.do_self()
---
进入enter
test
退出exit
None,None
if batch % 100 == 0:
loss,current = loss.item(),batch * len(X)
print(f"loss = {loss:>7f}, [{current:>5d}/{size:>5d}]")
'>‘右对齐,’<‘左对齐,’^'居中对齐
print('{:10s} and {:>10s}'.format('hello','world')) # 取10位左对齐,取10位右对齐
hello and world
更多格式化输出详见python基础_格式化输出(%用法和format用法)
__all__
__all__
表示对于该包中,有哪些子包或模块可以对外可见。
包的目录结构如下:
.
└── mypackage
├── __init__.py
├── subpackage_1
├── __init__.py
├── module_a.py
└── module_c.py
├── subpackage_2
├── __init__.py
├── module_b.py
# module_b.py
from package import *
print(dir())
sub_package1.module_a.aa()
---
NameError: name 'sub_package1' is not defined
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
# package.__init__.py
__all__ = ['sub_package1', 'sub_package2']
执行module_b.py
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sub_package1', 'sub_package2']
Traceback (most recent call last):
sub_package1.module_a.aa()
AttributeError: module 'package.sub_package1' has no attribute 'module_a'
#package.subpackage1.__init__.py
__all__ = ['module_a']
import package.sub_package1.module_a
执行module_b.py
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sub_package1', 'sub_package2']
aa
参考Python中的注解“@”
'''
@link:
@introduction: Python3.0之后加入新特性Decorators,以@为标记修饰function和class
'''
def spamrun(fn):
def sayspam(*args):
print("spam,spam,spam")
fn(*args)
def sayspam1(*args):
print("spam1,spam1,spam1")
fn(*args)
return sayspam1 #返回值为函数
def spamrun1(fn):
def sayspam2(*args):
print("spam2,spam2,spam2")
fn(*args)
return sayspam2 #返回值为函数
@spamrun1
@spamrun
def useful(a, b):
print(a * b)
if __name__ == "__main__":
useful(2, 5)
---
spam2,spam2,spam2
spam1,spam1,spam1
10
上面的代码等价于
spamrun1(spamrun(useful(2,5)))
or
if __name__ == "__main__"
useful = spamrun1(spamrun(useful))
useful(a,b)
这里只简单介绍了针对函数的用法,其实还可以针对class使用。
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.1",
author="wangxiaoxi1")
def mymethod1(f):
print(getattr(mymethod2, 'versionadded', 0))
print(getattr(mymethod2, 'author', 0))
print(f)
@attrs(versionadded="2.2",
author="wangxiaoxi2")
def mymethod2(f):
print(getattr(mymethod1, 'versionadded', 0))
print(getattr(mymethod1, 'author', 0))
print(f)
if __name__ == "__main__":
mymethod1(1)
mymethod2(2)
---
2.2
wangxiaoxi2
1
2.1
wangxiaoxi1
2
通过getattr获取类,方法中的属性值。其中注解@attrs是mymethod1,mymethod2方法中的内置方法,是其属性。
参考
总结如下:
类和实例都可以调用static method,在实例化对象时,并不会为其实例化static method,因此参数中没有self
。
class method可以用来为一个类创建一些预处理的实例.
代码如下:
@staticmethod:
- static method中没有
self
参数,也没有cls
参数class Pizza(object): @staticmethod def mix_ingredients(x, y): return x + y def cook(self): return self.mix_ingredients(self.cheese, self.vegetables) pizza = Pizza() print(pizza.mix_ingredients == Pizza.mix_ingredients) print(pizza.cook == Pizza.cook) --- True False
@classmethod:
- 返回实例化的类对象,这样就不用重载类,修改
__init__
方法了。可以通过@classmethod实现构造函数重载。- 这里要注意的是,第一个参数为cls,表示这个类
class Pizza1(object): @classmethod def wash(cls, vegetable_num): print(f"wash {vegetable_num} vegetable") return cls() #返回实例化的类对象 def cook(self,cheese_num,vegetable_num): print(f"cook {cheese_num} cheese and {vegetable_num} vegetable") pizza_ = Pizza1.wash(5) pizza_.cook(2,4) --- wash 5 vegetable cook 2 cheese and 4 vegetable
class DateM(object): def __init__(self,year=0,month=0,day=0): self.day = day self.month = month self.year = year @classmethod def get_date(cls,string_date): year,month,day = map(int,string_date.split('-')) date1 = cls(year,month,day) #使用__init__构建对象 return date1 def out_date(self): print(f"year = {self.year}") print(f"month = {self.month}") print(f"day = {self.day}") date = DateM.get_date('2021-7-4') date.out_date() --- year = 2021 month = 7 day = 4
#!/usr/bin/python3
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:
print (x, end=" ")
---
1 2 3 4
也可以使用next函数
#!/usr/bin/python3
import sys # 引入 sys 模块
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
while True:
try:
print (next(it))
except StopIteration:
sys.exit()
未使用yield
的斐波那契數列实现
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
fab(5)
---
1
1
2
3
5
使用yield
,将print
改为yield
,就在保持简洁性的同时获得了 iterable 的效果。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b, b + 1 #使用 yield可以返回多个值
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
---
1 2
1 2
2 3
3 4
5 6
yield和return的比较:
yield输出的结果可以在方法外被读取(生成当前值),yield
后续的操作会继续执行,直至下一次yield
。
如果将上面的yield
改为return
,return
后面的语句就不执行了,而且无法当做迭代器使用,会报
Traceback (most recent call last):
File "E:/研究生任务/摔倒检测工具包/test/__init__.py", line 10, in <module>
for n in fab(5):
TypeError: 'int' object is not iterable
ModuleNotFoundError
报错..config
导入模块报ModuleNotFoundError
错参考
在报错模块中添加
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
如果执行文件和模块不在同一目录,这时候直接import是找不到自定义模块的。如下图:
sys模块是python内置的,因此我们导入自定义模块的步骤如下:
sys.path.append(path)
函数来导入自定义模块所在的目录这时候 main.py 这样写:
# main.py
# -*- coding: utf-8 -*-
import sys
sys.path.append(r"C:\Users\Pwcong\Desktop\python")
import pwcong
pwcong.hi()
最后执行main.py文件,最终输出 hi
,第二种方式完成。
__main__.XX
参考程序运行出现ModuleNotFoundError: No module named __main__.XX';
, __main__
is not a package
当导入自己写的包时,出现上述情况,一般是因为路径问题,运行主程序是在哪个路径,则包里的程序的所导入的包也应该加上此路径。
.so
文件参考
python文件打包/导入 .so 文件
Ubuntu系统下编译.so文件报错:undefined symbol: _Py_ZeroStruct
在使用Flask写服务器时,发现python的dict
类型无意间变成了MappingProxyType
,连dict
里面对应key的value也不再是类对象,变成了type类型。
主要原因是:
Flask的app默认单线程运行,对于同个key-value对象,如果同一时刻已经有人对它进行操作,则另一个人想同时去操作它就会被禁止,key-value对象为可读状态。
解决方法是:
app(threaded = True)
# 不可变映射类型,(字典)MappingProxyType
'''
python3.3开始,types模块中引入了一个封装类名叫MappingProxyType
如果给这个类一个映射,它会返回一个只对映射视图.
虽然是个只读的视图,但是它是动态的,这意味着如果对原映射做出了改动,
我们可以通过这个视图观察到,但是无法通过这个视图对原映射做出修改
'''
```python
#示例
from types import MappingProxyType
#创建一个集合
index_a = {'a' : 'b'}
#创建index_a的映射视图
a_proxy = MappingProxyType(index_a)
print(a_proxy)
a_proxy['a']
# #不能对a_proxy视图进行修改
# a_proxy['b'] = 'bb'
#但是可以对原映射进行修改
index_a['b'] = 'bb'
print(a_proxy)
```
{'a': 'b'}
{'a': 'b', 'b': 'bb'}
https://www.cnblogs.com/ydf0509/p/8298551.html
参考
参考flask + nginx + uWSGI部署
将tracks,p1,good封装成zip,再解封成元组
for i, (tr, (x, y), flag) in enumerate(zip(tracks, p1.reshape(-1, 2), good)):
...
参考python生成requirements.txt的两种方法
如安装 pipreqs 即可以导出项目依赖的包:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pipreqs
之后在进入项目目录下,执行即可
pipreqs ./ --encoding=utf8 #如果requirement.txt已存在,则 pipreqs . --encoding=utf8 --force
#图片路径
im_dir = 'test/'
'''图片路径下的图片命名格式为000001.jpg 000002.jpg ……. 00100.jpg……'''
for i in range(1,num):
im_name = os.path.join(im_dir, str(i).zfill(6)+'.jpg') #Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
frame = cv2.imread(im_name)
print(im_name)
---
test/000001.jpg
test/000002.jpg
test/000003.jpg
test/000004.jpg
test/000005.jpg
test/000006.jpg
test/000007.jpg
test/000008.jpg
test/000009.jpg
test/000010.jpg
test/000011.jpg
test/000012.jpg
test/000013.jpg
test/000014.jpg
test/000015.jpg
...
利用函数进行迭代器元素的过滤,比单纯使用运算符更强大
'''filter(function, iterable) 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。'''
def is_odd(n):
return n % 2 == 1
tmplist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
newlist = list(tmplist)
print(newlist)
---
[1, 3, 5, 7, 9]
__call__
方法的使用(“实例对象 -> 可调用对象”)参考nn.Model中的forward()前向传播不调用
可调用对象:
关于__call__方法,不得不先提一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数callable。
如果在类中实现了__call__方法,那么实例对象也将成为一个可调用对象。
Ex1:
'''Ex1'''
'''__call__方法的初次使用'''
class A():
def __call__(self):
print('i can be called like a function')
a = A()
a()
print()
---
i can be called like a function
Ex2:
通过实现__call__方法,让实例化的对象无需通过指定方法完成函数调用,直接通过B()(x)完成默认的call函数的调用
'''Ex2'''
'''通过实现__call__方法,让实例化的对象无需通过指定方法完成函数调用,直接通过B()(x)完成默认的call函数的调用'''
class B(object):
def __call__(self, param):
print('我在__call__中,传入参数', param)
res = self.forward(param)
return res
def forward(self, x):
print('我在forward函数中,传入参数类型是值为: ', x)
return x
b = B()
x = b("Hello, my call")
print(x)
print()
---
我在__call__中,传入参数 Hello, my call
我在forward函数中,传入参数类型是值为: Hello, my call
Hello, my call
这也解释了pytorch中forward的实现原理
但是在torch.nn.Module
中,实际上没有使用__call__
,而是使用如下方式
def _forward_unimplemented(self, *input: Any) -> None:
raise NotImplementedError
class Module():
forward: Callable[..., Any] = _forward_unimplemented
...
def _call_impl(self, *input, **kwargs):
...
__call__ : Callable[..., Any] = _call_impl
可以发现,Module.py
文件中是没有forward
方法的,如果在子类Net
中没有实现forward
,会在_forward_unimplemented
中报错raise NotImplementedError
,这也说明forward
方法是实现,而不是重写。 但是在模拟时报错,提示实例对象不是可调用对象
'''参考'''
'''Ex3: 模拟Module, Net'''
from typing import Callable,Any
def _forward_unimplemented(self, *input: Any):
print("是我_forward_unimplemented绑定的forward, 我是个未实现的forward方法")
class Module():
def __init__(self):
print("Module参数初始化")
forward: Callable[..., Any] = _forward_unimplemented
class Net(Module):
def __init__(self):
super(Net, self).__init__()
print("Net参数初始化")
def forward(self,x):
print(f"Net调用forward,执行x = {x}")
return x ** 2
net = Net()
res = net(5) #TypeError: 'Net' object is not callable(该实例对象不是可调用对象)
print(res)
---
Module参数初始化
Net参数初始化
TypeError: 'Net' object is not callable(该实例对象不是可调用对象)
这里就不深究原因了,typing模块的Callable的使用参考
参考Python如何截图保存的三种方法
import time
from PIL import ImageGrab
if __name__=="__main__":
pic = ImageGrab.grab()
pic.save("picture.jpg")
import glob
import os
imgDir = "../dataset/fire/"
total_readPaths = glob.glob(os.path.join(imgDir, "*.*"))
for path in total_readPaths: #遍历所有文件路径
...
参考 https://www.cnblogs.com/bigtreei/p/9316369.html
from pathlib Path
'''
目录结构如下:
└─fire
│ manhole_close000.jpg
│ manhole_close001.jpg
│
└─enhance
├─color
│ manhole_close000.jpg
│ manhole_close001.jpg
│
└─resize
manhole_close000.jpg
manhole_close001.jpg
'''
imgDir = "../dataset/fire/"
for p in Path(imgDir).iterdir():
#遍历子文件夹下所有文件
for s in p.rglob('*.jpg'):
print(s)
srcFile = './actwork/linkFile/allExtLinks.txt'
dstFile = './actwork/linkFile/allExtLinks-copy.txt'
try:
os.rename(srcFile,dstFile)
except Exception as e:
print(e)
print('rename file fail\r\n')
else:
print('rename file success\r\n')
存在的问题:由于python文件放置的位置不同(一个在主文件夹,一个在子文件夹),在调用模型时如果通过相对路径去访问权重文件,这就会导致不同python文件在访问这个权重文件时需要传入该权重文件相对于该python文件的路径,这就有点麻烦。如果想让模型对外透明,不需要用户输入权重文件的位置,想把权重文件路径写死,这里可以考虑将项目文件的根路径和权重文件实际在项目中的位置进行拼接即可。
存在问题的代码:
# 人脸检测器scrfd
scrfd_detetor = SCRFD("../../model/SCRFD/scrfd_500m_kps.onnx") # scrfd人脸定位
# 人脸身份识别器
sess = onnxruntime.InferenceSession('../../model/MobileNetV2_onnx/IDRecognition.onnx') # 通过onnx文件加载onnxruntime推理引擎
id_img_Dir = "../../data/id_dataset/"
修改后的代码:
import sys
import os
from pathlib import Path
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
from pathlib import Path
rootPath = str(Path(rootPath).parent) #'F:\\IdentityDetection\\ID_recognition'
# 人脸检测器scrfd
scrfd_detetor = SCRFD(rootPath + "/model/SCRFD/scrfd_500m_kps.onnx") # scrfd人脸定位
# 人脸身份识别器
sess = onnxruntime.InferenceSession(rootPath + '/model/MobileNetV2_onnx/IDRecognition.onnx') # 通过onnx文件加载onnxruntime推理引擎
id_img_Dir = rootPath + "/data/id_dataset/"
参考python中的GIL详解
参考
Python 的 dataclasses
Python中的数据类dataclass详解
在使用自定义类 Class时,存在
对象的描述不太友好
__init__
方法中重复代码 (示例中每个属性都需要写3遍)
需要自己实现__repr__
方法, 和比较方法__eq__
, __gt__
等
class Player:
def __init__(self, name, number, position, age, grade):
self.name = name
self.number = number
self.position = position
self.age = age
self.grade = grade
def __repr__(self):
return f'Player: \n {self.name}\t #{self.number}\t @{self.position}\t <{self.grade}>'
def __eq__(self, other):
return self.age == other.age
def __gt__(self, other):
return self.age > other.age
def swing(self, pos):
self.position = pos
dataclass 提供一个简便的方式创建数据类
默认实现__init__()
, __repr__()
, __eq__()
方法.
dataclass支持数据类型的嵌套
支持将数据设置为不可变
@dataclass
class Player:
number: int
position: str
age: int
grade: str
name: str = ""
参考python异常和错误
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
| +-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
其中BaseException是所有错误的基类。
参考 Python 对象按照某个属性排序
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __repr__(self):
return '(%s: %s)' % (self.name, self.score)
import functools # 排序引用包
def my_cmp(self, s):
"""
自定义排序方法
:param self:
:param s:
:return: 按照 成绩从大到小, 当相等后,安装字母 A - Z
"""
if self.score > s.score:
return -1
elif self.score < s.score:
return 1
else:
if self.name < s.name:
return -1
elif self.name > s.name:
return 1
else:
return 0
def testClassSort():
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77), Student('fbl', 88)] # 对象列表
print(sorted(L, key=functools.cmp_to_key(my_cmp))) # 调用自定义排序方法排序
Note:注意my_cmp
要有self
参数,否则会报TypeError: my_cmp() takes 1 positional argument but 2 were given