一、Python基础语法
1.1 基本运算
1.1.1 取幂运算
a=100
a**=10 #10000
1.1.2 除以
a/=10 #10.0
1.1.3 整除
a//9 #11
1.2 字符串的定义与相关操作
1.2.1 字符串的定义
字符串在Python
中有多种定义形式:
- 单引号定义法
- 双引号定义法
- 三引号定义法:与多行注释的写法一样,同样支持换行操作
- 使用变量接收它,它就是字符串
- 不使用变量接收它,就可以作为多行注释使用
1.2.2 字符串的引号嵌套
- 单引号定义法,可以内含双引号
- 双引号定义法,可以内含单引号
- 可以使用转义字符”
\
“来将引号解除效用- 例:
name = "\"黑马程序员\""
- 例:
1.2.3 字符串的拼接
使用”+
“号连接字符串变量或字符串字面量即可,但无法和非字符串类型进行拼接。
1.2.4 索引
word='Python'
word[0] #'P'
word[-1] #'n'
1.3 字符串的格式化与对齐
字符串的拼接有明显的劣势:
- 变量过多,拼接起来较麻烦
- 字符串无法和数字或其他类型完成拼接
1.3.1 占位型拼接
%s
表示:占位s
表示:将变量变成字符串放入占位的地方
name = "黑马程序员"
message = "学IT就来 %s" %name
print(message)
多个变量占位,变量要用括号括起来,并按照占位的顺序填入:
class_num = 57
avg_salary = 16781
message = "Python大数据学科,北京%d期,毕业平均工资:%d" % (class_num,avg_salary)
print(message)
可以使用辅助符号”m.n
“来控制数据的宽度和精度:
m
控制宽度,要求是数字(设置的宽度小于数字自身将不生效).n
控制小数点精度,要求是数字,会进行小数的四舍五入
1.3.2 快速格式字符串的方式
f"内容{变量}"
(f
意为format
)
这种方式不理会类型,且不作精度控制,适合对精度没有要求的时候快速使用。
1.3.3 对齐字符串
^
:居中,后面带宽度<
:左对齐,后面带宽度>
:右对齐,后面带宽度:
后面带填充的字符,只能是一个字符,不指定则是默认用空格填充
print("{:>5}".format(1)) #宽度为5,右对齐
print("{:>5}".format(10))
print("{:>5}".format(100))
print("{:>5}".format(1000))
输出结果为:
1
10
100
1000
数字 | 格式 | 输出 | 描述 |
---|---|---|---|
3.1415926 | {:.2f} |
3.14 | 保留小数点后两位 |
3.1415926 | {:+.2f} |
+3.14 | 带符号保留小数点后两位 |
-1 | {:-.2f} |
-1.00 | 带符号保留小数点后两位 |
2.71828 | {:.0f} |
3 | 不带小数 |
5 | {:0>2d} |
05 | 数字补零 (填充左边, 宽度为2) |
5 | {:x<4d} |
5xxx | 数字补x (填充右边, 宽度为4) |
10 | {:x<4d} |
10xx | 数字补x (填充右边, 宽度为4) |
1000000 | {:,} |
1,000,000 | 以逗号分隔的数字格式 |
0.25 | {:.2%} |
25.00% | 百分比格式 |
1000000000 | {:.2e} |
1.00e+09 | 指数记法 |
13 | {:>10d} |
13 | 右对齐 (默认, 宽度为10) |
13 | {:<10d} |
13 | 左对齐 (宽度为10) |
13 | {:^10d} |
13 | 中间对齐 (宽度为10) |
11 | '{:b}'.format(11) '{:d}'.format(11) '{:o}'.format(11) '{:x}'.format(11) '{:#x}'.format(11) '{:#X}'.format(11) |
1011 11 13 b 0xb 0XB |
进制 |
# 正号表示正数
print("{:+2f}".format(3.14)) #+3.140000
print("{:-2f}".format(-1)) #-1.000000
# 不带小数的
print("{:.0f}".format(3.23123131)) #3
# 以逗号为分隔符的
print("{:,}".format(100000)) #100,000
# 表示一个百份比
print("{:.2%}".format(0.25)) #25.00%
1.4 切片操作
简单切片指的是这样的切片形式:a[start:stop]
,其行为是得到下标在这样一个前闭后开区间范围内的元素,其中start
和stop
为负数时,简单看作是负数下标对应的位置即可。
word[0:2] #'Py'相当于数学中的[0,2)
z = [1,2,3,4,5]
z[:-1] #[1, 2, 3, 4]
1.5 Python中的基本概念
- 列表
list
x1=[1,2,3,4]
- 元组
Tuple
x2=(1,2,3,4,5,6,7)
- 步长
print(x2[1::2]) #第三个参数代表步长,答案为(2,4,6)
- 序列重复
x3="123"*5 #123123123123123
二、列表
列表的下标索引,从前向后从0
开始,每次+1
;从后向前从-1
开始,每次-1
。
2.1 追加元素
#一个元素
x1.append("Hello") #仅对列表使用append,[1,2,3,4,"Hello"]
#追加多个元素
x1.extend([6,7])
2.2 中间插入元素
x1.insert(2,"GREAT") #x1=[1, 2, 'GREAT', 3, 4, 'Hello', 6, 7]
2.3 删除元素
x1.remove(3) #remove会删除查找到的第一个元素,并且没有返回值
del x1[2] #删除指定元素
element = x1.pop(2) #取出(并删除)元素,并用一变量接收返回值
2.4 反转列表
x1.reverse()
2.5 排序
x1.sort()
三、元组
元组一旦定义完成,就不可修改。
特例:
可以修改元组内的
list
内容(修改元素、增加、删除、反转等)。
3.1 只有一个元素的元组定义
a1=("Hello",)
print(a1,type(a1)) #<class 'tuple'>
3.2 统计某元素在元组中出现的次数
a1.count("Hello")
3.3 元组的嵌套
t = ((1,2,3),(4,5,6))
num = t[1][2] #6
注:
元组支持
for
循环。
四、字典
4.1 格式
每个元素均由”:
“和键值对构成,”:
“左边称为键(Key),右边称为值(Value)。
english=
{
"we":"我们",
"world":"世界",
"company":"公司"
}
print(english,type(english)) #运行结果为:{'we':'我们','world':'世界','company':'公司'} <class 'dict'>
english["world"]="城市" #修改/增加元素
4.2 删除、清空与拷贝
del english["city"] #删除元素
english.clear() #清空元素
english1=english.copy() #复制一个具有相同键值对的字典
4.3 创建新词典
seq=("name","age","class")
stu1=dict.fromkeys(seq)
print("不指定默认值",stu1) #{'name':None,'age':None,'Class':None}
stu2=dict.fromkeys(seq,15)
print("指定默认值",stu2) #{'name':15,'age':15,'Class':15}
4.4 返回键对应的值
print(english.get("world")) #输出"世界",若字典中没有则返回None,可以指定默认值,如下
print(english.get("city","未知")) #输出"未知"
print(english.keys()) #输出:dict_key(['we','world','company']),keys方法常用来判断一个键是否存在于字典中
print("是否存在world?","world" in english.keys()) #True
4.5 返回列表
print(english.items()) #输出:dict_items([('we','我们'),('world','世界'),('company','公司')])
4.6 遍历字典
for k,v in english.items():
print(k,"->",v)
#输出:we->我们
# world->世界
# company->公司
五、集合
5.1 集合的格式
empty = set() #空集合
number = {1,2,3} #数字集合
mix = set([1,"您好",3.14]) #混合类型集合,输出{3.14,1,'您好'}
5.2 集合的基本操作
集合的基本操作主要有增加,减少,取交、并、差等。
number = {1,2,3}
number.add(5) #{1,2,3,5},增加元素可以增加重复的(相当于不增加)
number.remove(3) #{1,2},减少元素不可以用于不存在的元素,不然会报错
设n1={1,3,5},n2={2,7,1,3}:
- 交:
n1&n2
,结果是{1,3}
- 并:
n1|n2
,结果是{1,2,3,5,7}
- 差:
n1-n2
,结果是{5}
- 对称差:
n1^n2
,结果是{2,5,7}
六、推导式(解析式)
6.1 列表推导式
odd=[x for x in range(10) if x%2!=0]
print(odd) #输出为[1,3,5,7,9]
6.2 字典推导式
d1={n:n**2 for n in range(5)}
print(d1) #{0:0,1:1,2:4,3:9,4:16}
d2={v:k for k,v in d1.items()}
print(d2) #{0:0,1:1,4:2,9:3,16:4}
6.3 集合推导式
s1={i**2 for i in [-1,-5,1,2,-2]}
print(s1) ##{1,4,25},推导时可以去除重复元素
七、流程控制
7.1 if判断
格式:
x=True
if x: #表达式
print("It is True!")
elif,else
7.2 while循环
x=1
while x<=10:
print(x)
x+=1
7.3 for循环
for x in (1,2,3,4,5)
print(x) #输出1 2 3 4 5(每个都将会换行)
for x in range(5) #range也可指定开始和结束数字,如range(1,10),输出从1到9
print(x) #输出0 1 2 3 4 5(每个都将会换行),注意从0开始
range
还可以指定序列步长,如range(1,10,2)
,即为1,3,5,7,9
(每个都将会换行)。
ps:pass
语句,不执行任何操作,其作用是保持程序结构的完整性
如:
if i==3:
pass
else:
print(i)
while
、for
后可以跟else
,当跳出循环时会执行else
的语句。但如果是因为break
产生的跳出循环,则不会执行else
的语句。
八、函数
8.1 可变参数
(1)*args
参数:获取到的是一个元组
def foo(*args):
print(args)
foo(1,"Shanghai") #输出(1,'Shanghai')
(2)**kwargs
参数:获取到的是一个字典
def foo(**kwargs):
print(kwargs)
foo(name='Jack') #输出{'name':'Jack'}
(3)组合使用
def cal(*args,**kwargs)
s=0
for i in args:
s+=i
print("输入的数字之和为",s)
for k,v in kwargs.items():
print(k,v)
cal(1,2,3,4,5,姓名="Jack") #结果为:输入的数字之和为15 姓名Jack
8.2 函数的多返回值
def test():
return 1,2
x,y = test()
print(x) #1
print(y) #2
8.3 函数的多种传参方式
8.3.1 位置参数
调用函数时根据函数定义的参数位置来传递参数。
8.3.2 关键字参数
def user_info(name,age,gender):
print(f"您的名字是:{name},年龄是:{age},性别是:{gender}")
#关键字传参
user_info(name="小明",age=20,gender="男")
#可以不按照固定顺序
user_info(age=20,gender="男",name="小明")
#可以和位置参数混用,位置参数必须在前,且匹配参数顺序
user_info("小明",age=20,gender="男")
8.3.3 缺省参数
def user_info(name,age,gender='男'):
print(f"您的名字是:{name},年龄是:{age},性别是:{gender}")
user_info(name="小明",age=20)
8.4 函数作为参数传递
函数作为参数传递是一种计算逻辑的传递,计算逻辑由被传入函数决定,而非数据的传递。
def test_func(compute):
result = compute(1,2) #确定compute是函数
print(result)
def compute(x,y):
return x + y
test_func(compute)
8.5 lambda匿名函数
lambda
关键字,可以定义匿名函数(无名称)。匿名函数只可以临时使用一次。
匿名函数定义语法:lambda 传入参数 : 函数体
注:
函数体就是函数的执行逻辑,只能写一行,无法写多行代码。
def test_func(compute):
result = compute(1,2) #确定compute是函数
print(result)
test_func(lambda x,y: x + y)
8.6 filter函数
filter
函数是内置函数,用于过滤序列,即过滤掉不符合条件的元素。
a1=[1,2,3,4,5,6,7,8]
a2=[item for item in filter(lambda x:x>5,a1)]
print(a2) #[6,7,8]
8.7 内置函数__call__()
Python
中一切皆对象,函数也是对象,同时也是可调用对象(callable
)。
一个类实例要变成一个可调用对象,只需要实现一个特殊方法__call__()
。
允许一个类的实例像函数一样被调用。实质上说,这意味着**x()
与x.__call__()
是相同的**。注意__call__
参数可变。这意味着你可以定义__call__()
为其他你想要的函数,无论有多少个参数。
class Entity:
def __init__(self, size, x, y):
self.x, self.y = x, y
self.size = size
def __call__(self, x, y):
'''改变实体的位置'''
self.x, self.y = x, y
e = Entity(1, 2, 3)
print(e.x)
print(e.y)
e(4, 5)
print(e.x)
print(e.y)
8.8 函数注释
格式为:(参数注释+返回值注释)
def function_name(a:expression,b:expression)->expression:
function body
return value
若需要获取函数注释,可以使用__annotations__
的方法:
print(function_name.__annotations__)
九、类和对象
9.1 类的属性
在Python中,构造函数就是类的__init__
方法,当一个类定义了__init__
方法后,类在实例化时会自动调用__init__
方法,用于创建新的类实例。在构造方法中我们可以初始化一些属性(或称成员变量、类变量)。
class Dog:
def __init__(self,name)
self.name=name
self.age=3
dog=Dog("旺财")
print(dog.name) #旺财
print(dog.age) #3
类中定义的方法第一个参数必须是“self”,即def play(self)
。
私有属性可用dog.__name
加两条下划线的形式,只能在类内进行修改。私有方法同理。
9.2 继承
定义要从哪个父类继承,只需在定义子类的名字后面的括号中填入父类的名字即可,如:
class Animal:
def __init__(self,name)
self.name=name
self.age=3
class Dog(Animal):
pass
9.3 多态
多态的意思就是多种形态。多态意味着即使不知道变量所引用的对象是什么类型,也能对对象进行操作。多态会根据类的不同表现出不同的行为。
9.3.1 继承方式实现多态
class Animal:
def say(self):
print("Animal")
class Dog(Animal):
def say(self):
print("Dog")
class Cat(Animal):
def say(self):
print("Cat")
dog=Dog()
dog.say() #Dog
cat=cat()
cat.say() #cat
ps:判断一个实例是否是某个对象可以用isinstance
函数,格式为isinstance(dog,Dog)
,返回True
orFalse
。
9.3.2 函数参数实现多态
#接上例
def animal_say(animal:Animal)
animal.say()
animal_say(dog)
animal_say(cat)
9.3.3 鸭子类型
鸭子类型中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口决定的,而是由当前方法和属性的集合决定的。
class Dog:
def say(self):
print("Dog")
class Cat:
def say(self):
print("Cat")
def animal_say(animal): #编写一个函数,使它接受一个类型为鸭子的对象
animal.say()
dog=Dog()
cat=Cat()
animal_say(dog)
9.4 静态方法和类方法
9.4.1 静态方法
定义静态方法时,在定义函数的上面一行添加“@staticmethod
”,且静态方法不再有第一个默认参数“self
”,本身也不能调用成员变量和成员方法。
class Animal
name="动物"
@staticmethod
def play()
print("Playing")
Animal.play()
9.4.2 类方法
类方法将该方法绑定在定义的类上,而不是绑定在实例上。在定义函数的上面一行添加“@classmethod
”,有初始参数”cls
“,类方法指向的是定义的类本身,类方法可以读取和修改类变量。
class Animal
name="动物"
@classmethod
def play(cls)
print(c"Playing")
Animal.play()
十、模块
模块就是一个包含了Python定义和声明的”.py”文件。在完成一个”.py”文件后,在与其同目录的文件可以使用这个模块,即import fibs
。如果要导入模块中的一个指定的部分到当前命名空间中,可用from fibs import fib,fib2
。
10.1 获取模块名
模块的模块名可以通过全局变量”__name__
“获得。
import fibs
print(fibs.__name__) #fibs
print(__name__) #__main__
由此可知,在定义模块时,可通过看当前的”__name__
“变量是否为”__main__
“来判断当前文件是被运行还是作为模块被导入。
if __name__=="__main__"
print("直接运行")
else:
print("被作为模块导入")
10.2 dir函数
dir函数可以列出对象的模块标识符,包括函数、类和变量。模块也是对象,调用模块中的内容和调用对象中的内容的方法是一样的。
import fibs
fibs.fib(10)
print(fibs.fib2(5))
10.3 包
模块即一个py文件,通过“包”加以组织。“包”是一个包含模块,且至少包含一个__init__.py
的文件夹,模块中包含代码。
package9
|--__init__.py
|--fun1.py
|--fun2.py
package9/fun1.py
:
def print1():
print("fun1")
package9/fun2.py
:
def print2():
print("fun2")
__init__.py
:
if __name__ == "__main__":
print("作为主程序运行")
else:
print("package初始化")
demo.py
#导入package9包
from package9.fun1 import print1
from package9.fun2 import print2
print1()
print2()
10.4 常用标准库
10.4.1 math库
两个常量:圆周率和自然常数e,调用方式为:math.pi
,math.e
。
运算函数:向上取整,如math.ceil(1.7)
,结果为2;向下取整,如math.floor(1.7)
,结果为1。
对数函数(默认底数为e,可使用第二个参数来改变对数的底数)
平方根计算(sqrt),三角函数计算,角度(degree)弧度(radians)转换
10.4.2 random库
random.random
用于生成一个0-1的随机浮点数:0<=n<1.0
。
random.uniform(1,150)
用于生成一个指定范围内的随机浮点数。
random.choice(seq1)
会从给定的序列中获取一个随机元素。
import random
seq1=(1,15,8,97,22)
seq2=["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
print(random.choice(seq1))
print(random.choice(seq2))
random.shuffle(seq1)
用于将一个列表中的元素打乱(注意:原来的序列必须是可以修改的,故元组等类型不能作为其参数使用)。
十一、文件操作与IO
11.1 文件基本操作
打开文件:
file_name="10.1.py"
f=open(file_name)
文件模式:r+
,表示打开一个文件用于读写,文件指针将会放在文件的开头。
使用open
函数返回的是一个文件对象,然后通过使用read
方法从一个打开的文件中读取内容到字符串。写文件则用write
方法。write
方法返回写入文件的字符串的长度。
f=open("readme.txt")
txt=f.read()
print(txt)
若想在已有的文件内容后追加内容,可在打开文件时使用”a
“模式,这样就可以在文件中追加写入内容。
关闭文件用f.close()
。
11.2 按行读/写文件
11.2.1 按行读取文件内容
f.readline()
readlines
函数会将文件内容按行切割,返回一个list列表对象。(注意:readlines
函数会保留结尾的换行符,不会去掉换行符,直接print
列表元素会发现每次输出都跟随一个空白行)
f=open("a.txt","r+")
for line in f.readlines():
print(line)
此外还有直接迭代文件对象本身的操作:这是一种”惰性“读取文件的方式,只有迭代到需要读取的一行,才会真的执行读取操作。
f=open("a.txt","r+")
for line in f:
print(line)
11.2.2 按行写入文件内容
利用writelines
方法接收一个参数(必须是列表),列表的每个元素就是想写入的每行文本的内容。
f=open("writelines.txt","r+")
lines=[]
for i in range(10):
lines.append(str(i))
f.writelines(lines)
运行结果为0123456789
,说明其不会帮助我们在每行之后添加换行符。
i=1
f=open("numbers.txt","a") #利用追加模式,参数从w替换为a即可
while i <= 10:
f.write("{}\n".format(i)) #format()为格式化字符串的函数
i=i+1
f.close()
11.3 StringIO函数
对str操作,要把str写入StringIO
,需要先创建一个StringIO
对象,然后像文件一样写入即可。
from io import StringIO
f=StringIO()
f.write('hello')
f.write(' ')
f.write('world!')
print(f.getvalue()) #获得写入后的str,输出hello world!
要读取StringIO
,可以先用一个str初始化StringIO
,然后像读文件一样读取。其中strip()
方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。若参数不为空,则移除所有该参数,如print str.strip( '0' ); #去除首尾字符 0
。
from io import StringIO
f=StringIO('Hello!\nWorld!\nWelcome!\n')
while True:
s=f.readline()
if s=='':
break
print(s.strip())
11.4 BytesIO函数
from io import BytesIO
f=BytesIO()
f.write("您好".encode("utf-8")) #以指定的编码格式编码字符串
print(f.getvalue())
print(f.getvalue().decode("utf-8")) #以指定的编码格式解码字符串
输出结果如下:b'\xe6\x82\xa8\xe5\xa5\xbd'
您好
读取方式如下:
from io import BytesIO
f=BytesIO(b'\xe6\x82\xa8\xe5\xa5\xbd')
print(f.read().decode("utf-8")) #输出"中文"
11.5 序列化与反序列化
pickle.dumps
可以把任意对象序列化成bytes对象,然后写入文件中永久存储。
import pickle
class Student:
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
student1=Student("小明",15,"男")
print(pickle.dumps(student1))
十二、日期和时间
12.1 time函数
time函数用于返回当前时间的时间戳,time函数返回的是浮点数。
import time
now=time.time()
print("当前的时间戳是:%f" % now)
输出结果为:当前的时间戳是:1641976277.347599
。
12.2 localtime函数
localtime
函数的作用是将时间戳格式化为本地时间,返回struct_time
对象。localtime
函数有一个参数用于接收时间戳,如果调用函数时不提供时间戳, localtime
函数默认使用当前时间戳。
import time
print("当前时间",time.localtime())
print("0时间戳对应的时间",time.localtime(0))
12.3 datetime模块
datetime模块包含了日期和时间的所有信息。
12.3.1 date对象
表示在日历中的一个日期(包含年、月、日)。格式为date=datetime.date(2018,7,1)
。
12.3.2 一些方法
Today
方法/weekday
方法分别返回当天日期和当前星期数(星期一返回0,依此类推)。isoweekday
方法星期一返回1,依此类推。isoformat
方法返回日期格式为ISO格式,即“YYYY-MM-DD”字符串。strftime
方法可以格式化输出日期,如print(date.strftime("%Y-%m-%d"))
。对于时-分-秒,分别为%H:%M:%S
。
十三、多线程和并行
多线程是指在软件或者硬件上实现多个线程并发执行的技术。Python标准库中关于线程的主要是_thread
和threading
模块。
13.1 _thread模块
13.1.1 概述
核心是start_new_thread
方法,格式为:_thread.start_new_thread(function,args[,kwargs])
。线程使用参数列表args
(必须是元组)执行函数,可选的kwargs
参数指定关键字参数的字典。在单个线程执行时,别的线程也在”同步“地执行。
import time
import datetime
import _thread
date_time_format="%H:%M:%S"
def get_time_str():
now=datetime.datetime.now()
return datetime.datetime.strftime(now,date_time_format)
def thread_function(thread_id):
print("Thread %d\t start at %s"%(thread_id,get_time_str()))
print("Thread %d\t sleeping"%thread_id)
time.sleep(4)
print("Thread %d\t finish at %s"%(thread_id,get_time_str()))
def main():
print("Main thread start at %s"%get_time_str())
for i in range(5):
_thread.start_new_thread(thread_function,(i,))
time.sleep(1)
time.sleep(6)
print("Main thread finish at %s"%get_time_str())
if __name__ =="__main__":
main()
运行结果如下:
Main thread start at 17:44:03
Thread 0 start at 17:44:03
Thread 0 sleeping
Thread 1 start at 17:44:04
Thread 1 sleeping
Thread 2 start at 17:44:05
Thread 2 sleeping
Thread 3 start at 17:44:06
Thread 3 sleeping
Thread 0 finish at 17:44:07
Thread 4 start at 17:44:07
Thread 4 sleeping
Thread 1 finish at 17:44:08
Thread 2 finish at 17:44:09
Thread 3 finish at 17:44:10
Thread 4 finish at 17:44:11
Main thread finish at 17:44:14
13.1.2 线程锁
_thread.allocate_lock
方法返回一个Lock
对象。Lock
对象有三个方法:
【1】acquire方法:用于无条件地获取Lock对象(如果有必要,等待他被另一个线程释放,一次只有一个线程可以获取锁定)。
【2】release方法:用于释放锁,释放之前必须先锁定,
【3】locked方法:用于返回锁的状态,如果已被某个线程锁定,则返回True,否则返回False。
lock=_thread.allocate_lock()
lock.acquire()
locks.append(lock)
13.2 Threading模块
利用threading.Thread
创建线程。
import time
import datetime
import threading
date_time_format="%H:%M:%S"
def get_time_str():
now=datetime.datetime.now()
return datetime.datetime.strftime(now,date_time_format)
def thread_function(thread_id):
print("Thread %d\t start at %s"%(thread_id,get_time_str()))
print("Thread %d\t sleeping"%thread_id)
time.sleep(4)
print("Thread %d\t finish at %s"%(thread_id,get_time_str()))
def main():
print("Main thread start at %s"%get_time_str())
threads=[]
#创建线程
for i in range(5):
thread=threading.Thread(target=thread_function,args=(i,))
threads.append(thread)
#启动线程
for i in range(5):
threads[i].start()
time.sleep(1)
#等待线程执行完毕
for i in range(5):
threads[i].join() #阻塞线程,使用join后,后面的语句需要等当前进程完成之后才能执行
print("Main thread finish at %s"% get_time_str())
if __name__ =="__main__":
main()
运行结果如下:
Main thread start at 20:36:02
Thread 0 start at 20:36:02
Thread 0 sleeping
Thread 1 start at 20:36:03
Thread 1 sleeping
Thread 2 start at 20:36:04
Thread 2 sleeping
Thread 3 start at 20:36:05
Thread 3 sleeping
Thread 0 finish at 20:36:06
Thread 4 start at 20:36:06
Thread 4 sleeping
Thread 1 finish at 20:36:07
Thread 2 finish at 20:36:08
Thread 3 finish at 20:36:09
Thread 4 finish at 20:36:10
Main thread finish at 20:36:10