python3基础知识重点

[toc]

一,python3基础知识重点

1, 数据与存储

1
2
3
4
5
内存:
抽象: 一个开关,有两种状态,开启和关闭,一种状态对应1,另一种状态对应0,把八个开关放到一个房间里,这个房间称为"一个字节" ,一个开关代表"一位" 。每个房间都有门牌号,看作"地址", 把无数个房间堆叠起来组成摩天大楼,可以把摩天大楼看成"内存"

数据存储: 计算机存储数据,先开辟内存空间,再存储数据。计算机开辟内存的最小单位是字节。在存储数据时。用
最高位标示符号,1表示负数,0表示正数。

2,python数据类型

1, Number(数字)

1
2
3
整数
浮点数(小数)
复数

2, String(字符串)

3, Boolean(布尔值)

4, None(空值)

5, list(列表)

6, tuple(元组)

7, dict(字典)

8, set(集合)

标识符

1
2
3
4
5
6
7
8
9
10
11
12
13
什么是标识符
是一串字符串(注意: 字符串未必是标示符)
规则
只能由字母,数字,下划线组成
开头不能是数字
不能是python的关键字
区分大小写
见名知意
遵循驼峰原则
作用
给变量,函数等命名
注意
在python3中,非ASCLL标识符也是允许的

查看关键字

1
2
3
4
5
import keyword

print(keyword.kwlist)

['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

1,浮点数

1
2
3
4
5
6
7
8
print(10 / 2)  #正如您之前看到的,两个整数相除将产生一个浮点数。
一个浮点数也是通过在两个浮点数或者在一个浮点数和一个整数上运算来产生的。
print(6 * 7.0)
print(5 + 2.32)
结果:
5.0
42.0
7.32

不可变对象

Python 中一切皆对象,每一个对象都有一个唯一的标示符(id())、类型(type())以及值。对象根据其值能否修改分为可变对象和不可变对象,其中数字字符串元组属于不可变对象,字典以及列表字节数组属于可变对象。而“菜鸟”常常会试图修改字符串中某个字符。看下面这个例子:

1
2
3
4
5
6
7
teststr = "I am a string"
teststr[11]='h'
print(teststr)

这样会报错

如果要修改字符串, 可以重新给生成一个字符串,或者将字符串拆解成数组,修改完成后再合并成字符串

类型转换

在 Python 中,涉及到一些类型是不能完成某些操作的。

例如,您不能将包含数字2和3的两个字符串添加到一起以生成整数5,因为操作会将在字符串拼接为“23”。

解决方案是类型转换。 在这个例子中,你将使用 int 函数将字符串转成整数。

1
2
3
4
5
print("2" + "3")
print(int("2") + int("3"))
结果
23
5

另一个类型转换的例子是将用户输入(会自动转成一个字符串)转换为数字(整数或浮点数),以便进行计算。

1
2
3
4
>>> float(input("Enter a number: ")) + float(input("Enter another number: "))
Enter a number: 30
Enter another number: 2
32.0

python 中文编码

前面章节中我们已经学会了如何用 Python 输出 “Hello, World!”,英文没有问题,

但是如果你输出中文字符”你好,亿动”就有可能会碰到中文编码问题。

解决方法很简单, 只要在文件开头加入 # -*- coding: UTF-8 -*- 或者 #coding=utf-8 就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/python
# -*- coding: UTF-8 -*-

print("你好,亿动")

#编码
#encode(encoding="utf-8", errors="strict")
str51="yichen is a good man"
data52= str51.encode("utf-8")
print (data52)
# ignore 忽略错误
#解码 注意: 要与编码时的格式一致。
#decode()
str53= data52.decode("utf-8" ,"ignore")
print (str53)

2, 字符串

字符串详细格式化和内置函数方法参考1.1python字符串内置函数总结文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#创建字符串
str1 = "yichen is a good man!"
str3 = "yichen is a nice man!"
str5 = "yichen is a handsome man!"

'''
字符串运算
'''
#字符串连接
str6 = "yichen is a "
str7 = " good man!"
str8 = str6 + str7
print ("str6 = ", str6)
print ( "str7 = ", str7)
print ("str8 = ", str8 )
#输出重复字符串
str9 = "good"
str10 = str9 * 3
print ("str10 =", str10)
#访问字符串中的某一个字符
#通过索引下标查找字符。索引从0开始,字符串名[下标]
str11 = "yichen is a good man!"
print (str11[1])
#str11[1] = "a" # 字符串不可变

#截取字符串中的一部分
str13 = "yichen is a good man!"
str15 = str13[7:16]
str16 = str13[:6]
print ("str15 =" , str15)
print ("str16 =" , str16)
str17 = str13[16:]
print ("str17 =", str17)

str18 = "yichen is a good man "
print ("good" in str18)
print ("good1" not in str18)
#格式化输出
print ("yichen is a good man")
num = 10
str19 = "yichen is a nice man!"
f = 10.1267
print ("num =", num )
# %d %s %f 占位符
print("num = %d, \nstr19= %s,\n f = %.3f " % (num,str19, f))
#打印多行
print ('''
good
nice
handsome''')
#如果字符串中有很多字符串都需要转义。python允许用r 表示内部的字符串默认不转义
print ( r"\\\t\\")

3,布尔类型

Python 中的另一种类型是布尔类型。有两个布尔值:TrueFalse

可以通过比较值的方法来创建它们,例如通过使用相等的运算符 **==**。

1
2
3
4
5
6
7
8
9
10
11
>>> my_boolean = True
>>> my_boolean
True

>>> 2 == 3
False
>>> "hello Edong" == "hello Edong"
True
注意:
不要把赋值(一个等号)与比较(两个等号)混淆。
Python是区分大小写的,所以True与true是不同的。

空值:是Python里一个特殊的值,用None表示。None不能理解为0,因为0是有意义的。而None是一个特殊值。

4,列表

列表是 Python 中的另一种类型的对象。它们被用来存储索引的元素列表。

方括号中用逗号分隔元素来创建一个列表。

列表中的某个元素可以通过使用方括号中的索引来访问。

例如:

1
2
3
4
words = ["Hello", "world", "!"]
print(words[0])
print(words[1])
print(words[2])

通常情况下,列表包含单种数据类型的元素,但也可以包含几个不同的类型。

列表也可以嵌套在其他列表中

1
2
3
4
5
6
7
8
9
number = 3
things = ["string", 0, [1, 2, number], 4.56]
print(things[1])
print(things[2])
print(things[2][2])
结果
0
[1, 2, 3]
3

列表操作

1,列表中某个索引处的元素值可以被重新分配。

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
nums = [7, 7, 7, 7, 7]
nums[2] = 5
print(nums)
2,列表可以像字符串一样添加和相乘。
nums = [1, 2, 3]
print(nums + [4, 5, 6])
print(nums * 3)
结果
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

3,要查找某个值是否在列表中,可以使用 in 运算符。如果值在列表中出现一次或多次,则返回 True,否则返回 False

words = ["spam", "egg", "spam", "sausage"]
print("spam" in words)
print("egg" in words)
print("tomato" in words)
结果
True
True
False
4,要某个值是否不在列表中,可以使用 not 操作符:
nums = [1, 2, 3]
print(not 4 in nums)
print(4 not in nums)
print(not 3 in nums)
print(3 not in nums)
结果
True
True
False
False

列表函数

可以使用 append 方法将一个元素添加到现有列表的末尾。

1
2
3
4
5
6
7
8
nums = [1, 2, 3]
nums.append(4)
print(nums) #结果:
[1, 2, 3, 4]
nums.append([7,8,9])
print (nums)
结果: 1, 2, 3, 4, [7, 8, 9]]
append 是列表类的一个方法。

要获取列表中的项目数量,可以使用 len 函数。

1
2
3
4
nums = [1, 3, 5, 2, 4]
print(len(nums))
结果:
5

与 append 方法不同,len 是一个正常的函数,而不是一个方法。这意味着它写在被调用的列表之前。

insert 方法与 append 相似,不同之处在于它允许您在列表中的任何位置插入一个新元素,而不仅仅是在最后。

1
2
3
4
5
6
words = ["W3Cschool", "Good"]
index = 1
words.insert(index, "is")
print(words)
结果:
['W3Cschool', 'is', 'Good']

extend() 在末尾一次性追加另一个列表中的多个值

1
2
3
4
list = [1,2,3,4,5]
list.exend([6,7,8])
pirnt(list)
结果[1, 2, 3, 4, 5, 6, 7, 8]

index 方法找到列表项的第一个匹配项并返回它的索引。

如果该项目不在列表中,则会引发 ValueError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
letters = ['p', 'q', 'r', 's', 'p', 'u']
print(letters.index('r'))
print(letters.index('p'))
print(letters.index('z'))
2
0
ValueError: 'z' is not in list

列表还有一些很有用的功能和方法。

max(list): 返回具有最大值的列表元素

min(list): 返回具有最小值的列表元素

list.count(3): 返回一个元素3在一个列表中出现的次数

list.remove(3):从列表中删除一个元素的第一个匹配的结果

list.reverse():颠倒列表中的元素的顺序
list.pop() #移除列表中指定下标处的元素(默认移除最后一个元素)
list.clear() #清除列表中所有数据
list.sort() #排序 升序
list.copy() #深拷贝 内存的拷贝

5,元组

元组与列表非常相似,不过元组是不可变的

而且,它们使用圆括号创建,而不是方括号。

1
words = ("spam", "eggs", "sausages",)

你可以使用索引访问元组中的值,就像使用列表一样:

1
print(words[0])

尝试重新分配元组中的值会导致 TypeError。

1
words[1] = "cheese"

结果:

1
TypeError: 'tuple' object does not support item assignment

像列表和字典一样,元组也可以相互嵌套。也可以for循环取值

元组可以在没有括号的情况下创建,只需用逗号分隔值。

例如:

1
2
3
4
my_tuple = "one", "two", "three"
print(my_tuple[0])
结果:
one

元组比列表快,但是元组不能改变。

元组的截取

格式:元组名[开始下标:结束下标]

从开始小标开始截取,截取到结束小标之前

1
2
3
4
t1 = (1,2,3,4,5,6,7,8,9)
print(t1[3:7]
结果:
(4, 5, 6, 7)

len()

1
2
3
4
5
6
7
8
#len() 返回元组中元素的个数
t14 = (1,2,3,4,5)
print (len(t14))

#将列表转成元组
list = [1,2,3]
t15 = tuple(list)
print (t15)

6,字典

字典 是用于将任意键映射到值的数据结构。

列表可以被认为是在一定范围内具有整数键的字典。

字典可以用与列表相同的方式建立索引。

使用 字典[“键名”] 可以获取对应的值。

例如:

1
2
3
4
5
6
ages = {"Dave": 24, "Mary": 42, "John": 58}
print(ages["Dave"])
print(ages["Mary"])
结果:
24
42

就像列表一样,字典键可以被分配到不同的值。

但是,与列表不同,新的字典键也可以被赋值,而不仅仅是已经存在的字典键。

例如:

1
2
3
4
5
6
squares = {1: 1, 2: 4, 3: "error", 4: 16,}
squares[8] = 64
squares[3] = 9
print(squares)
结果:
{8: 64, 1: 1, 2: 4, 3: 9, 4: 16}

#遍历

1
2
3
4
5
6
7
8
9
10
11
squares = {1: 1, 2: 4, 3: "error", 4: 16,}

for key in squares:
print(key, squares[key])
结果:
1 1
2 4
3 error
4 16
for value in squares.values():
print(value) #直接输入值

要确定 key (键)是否在字典中,您可以使用 innot,就像你可以使用列表一样。

1
2
3
4
5
6
7
8
9
10
11
12
nums = {
1: "one",
2: "two",
3: "three",
}
print(1 in nums)
print("three" in nums)
print(4 not in nums)
结果:
True
False
True

一个很有用的字典方法是 get 。它与索引做同样的事情,但是如果在字典中找不到键,它将返回另一个指定的值(默认情况下为“None”)。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
pairs = {1: "apple",
"orange": [2, 3, 4],
True: False,
None: "True",
}

print(pairs.get("orange"))
print(pairs.get(7))
print(pairs.get(12345, "not in dictionary"))
结果:
[2, 3, 4]
None
not in dictionary

7, 集合

集合是数据结构,类似于列表或字典。集合使用花括号set 函数创建。

它们与列表共享一些功能,例如使用 in 来检查它们是否包含特定项目。

1
2
3
4
5
6
7
8
9
10
num_set = {1, 2, 3, 4, 5}
word_set = set(["spam", "eggs", "sausage"])

print(3 in num_set)
print("spam" not in word_set)

结果:

True
False

集合在几个方面不同于列表,但共享几个列表操作,如 len

集合是无序的,这意味着他们不能被索引。

集合不能包含重复的元素。

由于存储的方式,检查一个项目是否是一个集合的一部分比检查是不是列表的一部分更快

集合使用 add 添加元素,而不是使用 append

remove 方法从集合中删除特定的元素; pop 删除随机的元素。

1
2
3
4
5
6
7
8
nums = {1, 2, 1, 3, 1, 4, 5, 6}
print(nums)
nums.add(-7)
nums.remove(3)
print(nums)
结果:
{1, 2, 3, 4, 5, 6}
{1, 2, 4, 5, 6, -7}

通常使用集合来消除重复的条目。

集合可以使用数学运算进行组合。

联合运算符 | 结合两个集合形成一个包含两个集合任一项目的新集合。

相交运算符& 获得两个集合共有的项目

差运算符 - 获取第一集合中的项目,但不是第二集合中的项目。

对称差分运算符^ 获取任集合中非共有的项目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}

print(first | second)
print(first & second)
print(first - second)
print(second - first)
print(first ^ second)
结果:
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{4, 5, 6}
{1, 2, 3}
{8, 9, 7}
{1, 2, 3, 7, 8, 9}

随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import random #引入模块
#1. 从序列的元素中随机挑选一个元素
print(random.choice([1,3,5,7,9]))
print(random.choice(range(5))) #range(5)==[0,1,2,3,4]
#产生一个1~100之间的随机数
r1= random.choice(range(100)) + 1
print(r1)
#从指定范围内,按指定的基数传递的集合中选取一个随机数
#random.randrange([start], stop[, step])
#start 指定范围的开始值,包含在范围内
#stop 指定范围的结束值,不包含在范围内
#step 指定的递增基数
print(random.randrange(1,100,2))

#随机生成[0,1]之间的数(浮点数)
print(random.random())

list = [1,2,3,4,5]
#将序列的所有元素随机排序
random.shuffle(list)
print(list)

#随机生成一个实数,他在[3,9]范围内。
print(random.uniform(3,9))

数据结构

正如我们在前面的课程中所看到的,Python支持以下数据结构:列表,字典,元组,集合。

何时使用字典:

- 当您需要键:值对之间的逻辑关联时。

- 当您需要基于自定义密钥快速查找数据时。

- 当你的数据不断修改时。请记住,字典是可变的。

何时使用其他类型:

- 如果您有一些不需要随机访问的数据集合,请使用列表。当你需要一个简单的,可迭代的频繁修改的集合可以使用列表。

- 如果你需要元素的唯一性,使用集合。

- 当数据无法更改时使用元组。

很多时候,元组与字典结合使用,例如元组可能代表一个关键字,因为它是不可变的。

3,while 循环

1
2
3
4
5
6
7
8
9
10
11
12
if语句
格式:
if 表达式:
语句

year = int(input("请输入年份"))
if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):
print ("是闰年")
else:
print ("不是闰年")

逻辑: 当程序执行到if语句时,首先计算"表达式"的值,如果"表达式的值"为真,那么执行if下的语句,如果表达式的值为假,则跳过整个if语句继续向下执行。

如果 if 语句的计算结果为 True,则 if 语句的代码块会运行一次,如果计算结果为 False,则不会运行。

while 语句是相似的,while 只要条件为True,while内部的代码块就会重复执行。

当条件为 False 时就停止 while 循环,程序继续往后执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
i = 1
while i <=5:
print(i)
i = i + 1
print("Finished!")
while 循环体中的代码被重复执行。这被称为迭代。

#计算1+2+3+*******+100
sum = 0
num = 1
while num <= 100:
sum += num
num += 1
print ("sum = %d" %(sum))

break 语句

要提前结束 while 循环,可以使用 break 语句。

在循环中遇到时,break 语句会立即结束循环。

1
2
3
4
5
6
7
8
9
10
i = 0
while 1==1:
print(i)
i = i + 1
if i >= 5:
print("Breaking")
break

print("Finished")
#在循环外部使用 break 语句会导致错误。

continue 语句

可以在循环内使用的另一个语句是 continue 语句。

与 break 不同的是,continue 语句是提前结束本次循环,进入下一次循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
i = 0
while True:
i = i +1
if i == 2:
print("Skipping 2")
continue
if i == 5:
print("Breaking")
break
print(i)

print("Finished")
结果
1
Skipping 2
3
4
Breaking
Finished

简而言之:continue 语句停止当前的迭代,并继续下一个。

在循环外部使用 continue 语句会导致错误。

4, 范围(range)

使用范围函数创建一个顺序的数字列表。

1
2
3
4
numbers = list(range(10))
print(numbers)
结果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Range 本身会创建一个 Range 对象,所以调用 list 函数将其转换为列表。

如果使用一个参数调用 Range,则会生成0到该参数值的对象。

如果使用两个参数调用范围,则会从第一个值到第二个值的对象。

例如:

1
2
3
4
5
6
7
8
numbers = list(range(3, 8))
print(numbers)

print(range(20) == range(0, 20))
结果:
[3, 4, 5, 6, 7]

True

Range 可以有第三个参数,第三个参数决定了产生的序列的间隔。

1
2
3
4
numbers = list(range(5, 20, 2))
print(numbers)
结果:
[5, 7, 9, 11, 13, 15, 17, 19]

注意: 第三个参数必须是一个整数, 否则会报TypeError。

5,for 循环

使用 while 循环遍历列表需要相当多的代码,所以 Python 提供了 for 循环作为完成相同事情的快捷方式。

前一个例子中的代码可以用 for 循环来编写,如下所示:

1
2
3
4
5
6
7
8
words = ["hello", "world", "spam", "eggs"]
for word in words:
print(word + "!")
结果:
hello!
world!
spam!
eggs!

Python中的 for 循环就像其他语言的 foreach 循环一样。

for 循环通常用于重复某些代码一定次数。这是通过将循环与范围 range 对象结合来完成的。

1
2
for i in range(5):
print("hello!")

在 for 循环中使用 range 对象时不需要调用 list,因为它没有被索引,所以不需要列表。

6,函数

除了使用预定义的函数外,还可以使用 def 语句创建自己的函数。

这是一个名为 my_func 的函数的例子。它不需要任何参数,并打印 “你好,Loen” 三次。先定义函数,然后被调用。

函数中的代码块仅在调用函数时执行。

1
2
3
4
5
6
7
8
9
def my_func():
print("你好,Loen")
print("你好,Loen")
print("你好,Loen")
my_func();
结果:
你好,Loen
你好,Loen
你好,Loen

大部分函数都有参数。 下面的例子定义了一个带有一个参数的函数:

1
2
3
4
5
6
7
8
9
10
def print_with_exclamation(word):
print(word + "!")

print_with_exclamation("皮卡丘")
print_with_exclamation("可达鸭")
print_with_exclamation("小火龙")
结果:
皮卡丘!
可达鸭!
小火龙!

正如你所看到的,参数是在括号内定义的。

使用逗号分隔多个参数

1
2
3
4
5
6
7
8
def print_sum_twice(x, y):
print(x + y)
print(x + y)

print_sum_twice(3, 8) #相当于把用户输入的两个参数计算相加,然后输出,定义的参数不一样结果也不一样。
结果:
11
11

函数参数可以在函数内部当变量使用。但是,它们不能在函数的定义之外被引用。函数内部创建的其他变量也不能在函数外部被引用

1
2
3
4
5
6
7
8
9
def function(variable):
variable += 1
print(variable)

function(7) #这个函数就是输出参数值+1
print(variable) #外部引用会报错
结果:
8
NameError: name 'variable' is not defined

默认参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#概念: 调用函数时,如果没有传递参数,则使用默认参数
# 要使用默认参数,最后将默认参数放到最后。
def myPrint1(str = "yichen is a good man ", age = "18"):
print (str, age)

myPrint1()

'''
不定长参数
概念: 能处理比定义时更多的参数


'''
#加了*号的变量存放所有为命名的变量参数,如果在函数调用时没有指定参数,它就是一个空元组
def func (name, *args):
print(name)
print(type(args))
for x in arr:
print(x)
func("yichen","good","nice")

#**代表键值对的参数字典。
def func2(**kwargs):
print(kwargs)
print(type(kwargs))

func2(x=1,y=2,z=3)

#这种接收任意参数。
def func3(*args, **kwargs):
pass

7,函数返回值

某些函数(如 int 或 str)会返回一个稍后可用的值。 定义的函数可以使用 return 语句执行此操作。 return 表达式可以不写,相当于return None

形参(形式参数): 定义函数时小括号里面的变量,本质是变量

实参(实际参数): 调用函数时给函数传递的数据,本质是值。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
def max(x, y):
if x >=y:
return x
else:
return y

print(max(4, 7)) #4不>= 7(y),所以返回else的内容7
z = max(8, 5)
print(z) #条件成立,所以返回x(8)
结果:
7
8

return 语句不能在函数定义之外使用。

定义一个函数比较参数长度,并返回最短的一个。

1
2
3
4
5
6
7
8
9
def shortest_string(x, y):
if len(x)<=len(y):
return x
else:
return y

print(shortest_string("hallo","ni"))
结果:
ni

一旦你从一个函数返回一个值,函数立即停止执行。返回语句之后的任何代码都不会执行。

例如:

1
2
3
4
5
6
7
8
def add_numbers(x, y):
total = x + y
return total
print("This won't be printed") #这个就不会执行了

print(add_numbers(4, 5)) #返回9
结果:
9

函数与其他任何类型的值一样。可以将它们重新分配给变量,并在稍后由这些变量名称引用函数。

1
2
3
4
5
6
7
8
9
def multiply(x, y):
return x * y

a = 4
b = 8
operation = multiply
print(operation(a, b)) #operation(a,b)等于 multiply(a,b)函数
结果:
32

函数也可以做为其他函数的参数。(PS:建议大家自己打一遍,深刻感受加深理解)

1
2
3
4
5
6
7
8
9
10
11
12
13
def add(x,y):
return x+y

def subtract(x,y):
return x-y

def do_twice(func,x,y):
return func(func(x,y),func(x,y))
#func参数就变成了add函数了,变成了返回 func(func(5+10),func(5+10)) 等于func(15,15)等于 30

a = 5
b = 10
print(do_twice(add,a,b))

正如你所看到的,函数 do_twice 接收一个函数做为参数,并在它的函数内部调用它。

将函数“square”作为参数传递给函数“test”:

1
2
3
4
5
6
7
8
9
def square(x):
return x*x #返回42*42=1746

def test(func,x):
print(func(x)) #输出 func(42)等于输出square(42)

test(square,42)
结果:
1746

8, 模块

概述

目前代码比较少,写在一个文件中还体现不出什么缺点,但是随着代码量越来越多,代码就越来越难以维护。

为了解决难以维护的问题,我们把很多相似功能的函数分组,分别放到不同的文件中去,这样每个文件所包含的内容就相对较少,而且,对于每一个文件的大致功能可用文件名来体现。很多编程语言都是这么来组织代码结构,一个.py文件就是一个模块。

优点:

1、提高代码的可维护性

2、提高了代码的复用度,当一个模块完毕,可以被多个地方引用,

3、引用其他的模块(内置模块和三方模块和自定义模块)

4、 避免函数名和变量名的冲突

模块是其他人为完成常见任务而编写的一些代码,例如生成随机数字,执行数学运算等。

使用模块的基本方法是在代码顶部添加 import 模块名 。

格式: import module [, 模块1[,模块2][, 模块n]] 模块可以引入多个

使用 模块名.变量 或者 模块名.函数 访问模块中的变量和函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#引入模块
import random ,time,sys, os

#获取命令行参数的列表
print(sys.argv)

for i in sys.argv:
print(i)

name = sys.argv[1]
age = sys.argv[2]
hoby = sys.argv[3]
print(name, age, hoby)

#自动查找所需模块的路径的列表
print(sys.path)

for i in range(5):
value = random.randint(1, 6)
print(value)
结果:
2
5
1
3
2
代码使用 radom 模块中定义的 randint 函数打印1到6范围内的5个随机数。

如果您只需要某个模块的某些功能,就可以使用另一种导入方式。

使用 from 模块名 import 变量名 的形式,然后变量名可以像在代码中正常定义一样使用。

1
2
3
4
5
from math import pi

print(pi)
结果:
3.141592653589793

可以使用逗号分隔导入多个对象。例如:

1
from math import pi, sqrt

可以使用 * 导入模块中所有对象。例如: from math import *

注意: 通常不鼓励这样做,因为它会将代码中的变量与外部模块中的变量混淆。

程序内容的函数或者变量可以将模块中的同名函数覆盖

您可以使用 as 关键字给导入的模块或对象重命名。模块或对象名称较长或容易混淆的时候比较常用。

例如:

1
2
3
4
from math import sqrt as square_root
print(square_root(100))
结果:
10.0

一些常用的标准库

1
string,re,datetime,math,random,os,multiprocessing,subprocess,socket,email,json,doctest,unittest,pdb,argparse, sys

标准库可以完成的任务包括字符串解析,数据序列化,测试,调试和操作日期,电子邮件,命令行参数等等。

许多第三方 Python 模块都存储在 Python Package Index(PyPI)中。

最好的安装方法是使用 pip 的程序。Python 的发行版默认安装了 pip。如果没有安装 pip,也可以很容易通过在线安装。

Mac和Linux无需安装pip,自带

一旦拥有它,从 PyPI 安装库是很容易的。查找要安装的库的名称,转到命令行(对于Windows,是命令提示符),然后输入 pip install 模块名。完成此操作后,导入库并在代码中使用它。

使用 pip 是在大多数操作系统上安装库的标准方法,但是一些库已经为 Windows 预编译了二进制文件。这些是正常的可执行文件,可以让您使用 GUI 安装库,这与安装其他程序的方式相同。

1
2
#Pillow  非常强大的处理图像的工具库
pip install --upgrade pip #windows如果报错,则输入这行代码,升级

自定义模块

创建一个.py文件 为luke.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#一个.py文件就是一个模块

def sayGood():
print("luke is a good man")


def sayNice():
print("luke is a good nice")

def sayHandsome():
print("luke is a good handsome")

TT = 100
yy = 666

然后可以去其他文件通过文件名为模块的方式导入使用,一个模快只会被引入一次,不管你执行了多少次import。 防止模块被多次引入。格式:模块名.函数名或变量名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#引入自定义模块,不用加.py后缀
import luke
#引入自定义模块中的指定函数或变量
from luke import sayGood, yy


a = luke.sayGood()
print(a)
print(luke.sayNice())
print(luke.sayHandsome)
print(luke.TT)

sayGood()
print(yy)
结果:
luke is a good man
None
luke is a good nice
None
luke is a good handsome
None
100

luke is a good man
666

2,__name__属性:

模块就是一个可执行的.py文件,一个模块被另一个程序引入。我不想让模块中的模些代码执行,可以用__name__属性来使程序仅调用模块中的一部分。

每一个模块都有一个_name__属性,当其值等于”__main_\“时,表明该模块自身在执行,否则被引入其他文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#一个.py文件就是一个模块

#当前文件如果为程序的入口文件,则__name__属性的值为__main__
if __name__ =="__main__":
print("这是luke的.py文件")
else:
def sayGood():
print("luke is a good man")


def sayNice():
print("luke is a good nice")


def sayHandsome():
print("luke is a good handsome")

TT = 100
yy = 666
#从其他程序导入当前的模块的话,__name__就不等于__main__ ,一般是等于其他程序的名字,

9,异常

不同的异常是由不同的原因引起的。

常见的异常:

  • ImportError: 无法引入模块或包。
  • IndexError: 下标索引超出序列边界;
  • NameError: 使用一个还未赋予对象的变量;
  • SyntaxError: 代码逻辑语法出错,不能执行;
  • TypeError: 传入的对象类型与要求不符;
  • ValueError: 传入一个不被期望的值,即使类型正确。
  • KeyError: 试图访问你字典里不存在的键。
  • IOError: 输入输出异常。

Python还有其他一些内置的异常,比如 ZeroDivisionError 和 OSError 。

第三方库也经常定义自己的异常。

1,异常处理

为了处理异常,并在发生异常时调用代码,可以使用 try/except 语句。

try 块包含可能会引发异常的代码。如果发生该异常,try 块中的代码将停止执行,并且 except 块中的代码将被运行。如果没有错误发生,except 块中的代码不会运行。

例如:

1
2
3
4
5
6
7
8
try:
num1 = 5
num2 = 0
print (num1 / num2)
print("计算完成")
except ZeroDivisionError:
print("发生错误")
print("您尝试进行除0操作")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
格式:
try:
语句t
except 错误码 as e:
语句1
except 错误码 as e:
语句2
else:
语句e

注意: else语句可有可无
作用: 用来检测try语句块中的错误,从而让except语句捕获错误信息并处理

逻辑: 当程序执行到try-except-else语句时
1、 如果当try“语句t”执行出现错误,会匹配第一个错误码,如果匹配上就执行对应的“语句”
2、 如果当try“语句t”执行出现错误,没有匹配的异常,错误将会被提交到上一层的try语句,或者到程序的最上层。
3、如果当try“语句t”执行没有出现错误,执行else下的“语句e”(你得有定义else语句

#使用except带着多种异常

try:
print(5 / 0)
except (NameError, ZeroDivisionError):
print("出现了NameError或ZeroDivisionError")

#特殊
1、错误其实是class(类),所有的错误都继承自BaseException,所以在捕获的时候,它捕获了该类型的错误,还把子类一网打尽
try:
print(5 /0)
except BaseException as e:
print("异常1")
except ZeroDivisionError as e:
print("异常2")
结果:
匹配 异常1,后面的就匹配不到了。本来应该是要匹配异常2才是准确的,

2、跨越多层调用, main调用了func2,func2调用了func1,func1出现了错误,这时只要main捕获到了就可以处理
def func1(num):
print(1 / num)
def func2(num):
func1(num)
def main():
func2(0)

try:
main()
except ZeroDivisionError as e:
print("代码出错")

try 语句可以有多个不同的 except 块来处理不同的异常。除了使用圆括号的块外,还可以将多个异常放入一个单独的块中,使 except 块处理所有这些异常。

1
2
3
4
5
6
7
8
9
10
try:
variable = 10
print(variable + "hello")
print(variable / 2)
except ZeroDivisionError:
print("Divided by zero")
except (ValueError, TypeError):
print("Error occurred")

结果: Error occurred #匹配到了TypeError错误

没有指定任何异常的 except 语句将捕获所有错误。应该谨慎使用,因为他们可以捕捉到意想不到的错误并隐藏编程错误。

例如:

1
2
3
4
5
6
7
try:
word = "spam"
print(word / 0)
except:
print("发生错误")
结果:
发生错误

在处理用户输入时,异常处理特别有用。

2,finally 语句

为了确保某些代码不管发生什么错误都运行,可以使用 finally 语句。finally 语句放置在 try/except 语句的底部。

finally 语句中的代码总是在 try 中的代码执行之后运行,可能在 except 代码块中运行。

1
2
3
4
5
6
7
8
9
10
11
12
try:
print("Hello")
print(1 / 0)
except ZeroDivisionError:
print("Divided by zero")
finally:
print("这段代码无论如何都会运行")
结果:

Hello
Divided by zero
这段代码无论如何都会运行

如果在前面的一个块中发生未捕获的异常,也会运行 finally 语句中的代码。 对于文件处理就很有用,无论怎么样都要关闭文件

3,引发异常(rause)

您可以使用 raise 语句引发异常。

1
2
3
4
5
6
print(1)
raise ValueError
print(2) #这条就不会执行了
结果:
1
ValueError

您需要指定引发的异常的类型。

引发异常可以提供一些异常的描述。

1
2
3
4
name = "123"
raise NameError("Invalid name!")
结果:
NameError: Invalid name!

except 块下,raise 语句可以在没有参数的情况下使用来重新引发发生的异常。

1
2
3
4
5
6
7
8
9
try:
num = 5 / 0
except:
print("An error occurred")
raise
结果:
An error occurred

ZeroDivisionError: division by zero

可以在 except 块外面使用 raise 语句

4,断言(assert)

使用 assert 断言是一个非常好的习惯,python assert 断言句语格式及用法很简单。在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,不如在出现错误条件时就崩溃,这时候就需要 assert 断言的帮助。

assert 断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解 assert 断言语句为 raise-if-not,用来测试表示式,其返回值为假,就会触发异常。

断言是通过使用 assert 语句来执行的。

1
2
3
4
5
6
7
8
9
print(1)
assert 2 + 2 == 4
print(2)
assert 1 + 1 == 3 #这里出错,就不会输出下面的了
print(3)
结果:
1
2
AseertionError

程序员经常在函数的开始处放置断言来检查有效的输入,并且在函数调用之后检查有效的输出。

如果断言失败,assert 可以接受第二个传递给 AssertionError 的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
temp = -10
assert (temp >= 0), "Colder than absolute zero!"
结果:
AssertionError: Colder than absolute zero!

def func(num, div):
assert (div != 0), "div不能为0"
return num / div

print(func(10, 0))
结果:
assert (div != 0), "div不能为0"
AssertionError: div不能为0

AssertionError 异常可以像使用 try-except 语句的任何其他异常一样被捕获和处理,但是如果不处理,这种类型的异常将终止程序。

10,文件操作

1,打开文件

您可以使用 Python 来读取和写入文件的内容。

文本文件是很容易操作的。在编辑文件之前,必须使用 open 函数打开文件。

1
2
3
path = r"d:\py_work\filename.txt"

myfile = open(path, "r",encoding="utf-8")

open 函数的参数是文件的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
open(path, flag,[encoding],[errors])
path:要打开文件的路径
flag:打开方式
r 以只读的方式打开文件,文件的描述符放在文件的开头,默认参数
rb 以二进制格式打开一个文件用于只读,文件的描述符放在文件的开头
r+ 打开文件用于读写,文件的描述符放在文件的开头
w 打开一个文件只用于写入,如果该文件已经存在会覆盖,如果不存在则创建新文件
wb 打开一个文件只用于写入二进制,如果该文件已经存在会覆盖,如果不存在则创建新文件
w+ 打开一个文件用于读写,如果不存在则创建新文件
a 打开一个文件用于追加,如果文件存在,文件描述符将放到至文件末尾
a+
encoding:编码方式 encoding="utf-8" 默认是utf-8
errors:错误处理 errors="ignore" 忽略错误 常用的

如果文件与程序位于同一目录中,你可以直接使用文件名称。

您可以通过向 open 函数应用第二个参数来指定用于打开文件的模式。

参数 “r” 表示在读取模式下打开,这是默认设置。

参数“w”表示写入模式,用于重写文件的内容。

参数“a”表示追加模式,用于将新内容添加到文件末尾。

将“b”添加到某个模式中文件将以二进制模式打开它,该模式用于非文本文件(如图像和声音文件)。

例如:

1
2
3
4
5
6
7
8
9
# 写模式
open("filename.txt", "w")

# 读模式
open("filename.txt", "r")
open("filename.txt")

# 二进制写入模式
open("filename.txt", "wb")

文件被打开和使用后要记得关闭它。通过文件对象的 close 方法进行关闭。

1
2
3
file = open("filename.txt", "w")
# do stuff to the file
file.close()

2,读文件

可以使用 read 方法读取以文本模式打开的文件的内容。

1
2
3
4
5
6
path = r"d:\py_work\filename.txt"

file = open(path, "r")
cont = file.read()
print(cont)
file.close()

这将打印文件 “filename.txt” 的所有内容。

如果只要读取文件一部分内容,你可以提供一个数字作为 read 方法的参数。决定要读取的字符数。

是按照字符个数来读,不是字节数。

你可以进行多次调用来读取同一个文件对象,逐字节读取更多的内容。如果没有参数,read 返回文件的其余部分内容。

1
2
3
4
5
6
file = open("filename.txt", "r")
print(file.read(16))
print(file.read(4))
print(file.read(4))
print(file.read())
file.close()

打开utf-8格式编码的文件

1
file = open("filename.txt", "r", encoding="UTF-8")

在读取完文件中的所有内容之后,如果试图从该文件进一步读取,将会返回一个空字符串,因为您正试图从文件末尾进行读取。

1
2
3
4
5
6
7
8
9
10
file = open("filename.txt", "r")
file.read()
print("Re-reading")
print(file.read())
print("Finished")
file.close()
结果:
Re-reading

Finished

要检索文件中的每一行,可以使用 readlines 方法返回一个列表,其中每个元素是文件中的一行。

#若给定的参数数字大于0,返回实际size的字节行数

1
file.redlines(30)

seek方法修改描述符的位置

1
file.seek(10)

例如:

demofile.txt

1
2
3
Line 1 text
Line 2 text
Line 3 text

demo.py

1
2
3
4
5
file = open("demofile.txt", "r")
print(file.readlines())
file.close()
结果:
['Line 1 text\n', 'Line 2 text\n', 'Line 3 text']

您也可以使用 for 循环遍历文件中的行:

1
2
3
4
5
6
7
8
9
10
11
12
file = open("demofile.txt", "r")

for line in file:
print(line)

file.close()
结果:
Line 1 text

Line 2 text

Line 3 text

在输出中,行由空行分隔,因为 print 函数在其输出结束时自动添加新行。

整体代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
path = r"d:\py_work\filename.txt"
try:
myfile = open(path, "r",encoding="utf-8")
read = myfile.read(7) #输出7位字符
print(read)
print(myfile.read()) #输出剩余全部字符
print("**********")
myfile.seek(0) #把描述符清零
print(myfile.read()) #可以继续从开头开始读了
finally: #不管怎样都会执行
if myfile: #判断文件是否打开,如果打开则执行关闭文件
myfile.close()

3,写文件

要写入文件,请使用 write 方法,该方法将字符串写入文件。

例如:

1
2
3
4
5
6
7
8
9
file = open("newfile.txt", "w")
file.write("This has been written to a file")
file.close()

file = open("newfile.txt", "r")
print(file.read())
file.close()
结果:
This has been written to a file

“w” 模式如果文件不存在,将创建一个文件。

如果写入成功的话 write 方法返回写入文件的字节数。

1
2
3
4
5
6
7
msg = "Hello world!"
file = open("newfile.txt", "w")
amount_written = file.write(msg)
print(amount_written)
file.close()
结果:
12

要确保文件在使用后始终关闭,避免浪费资源是一种好的做法。一个方法是使用 tryfinally

1
2
3
4
5
6
try:
f = open("newfile.txt")
print(f.read())
finally:
print("即使发生错误,这可以确保文件始终关闭。")
f.close()

一个替代方法是使用语句。这将创建一个临时变量(通常称为f),该变量只能在 with 语句的缩进块中访问。

1
2
with open("newfile.txt" ,"r" ,encoding="utf-8") as f:
print(f.read())

在 with 语句结束时,即使文件内部发生异常,文件也会自动关闭。

11,列表切片

列表切片(List slices)提供了从列表中检索值的更高级的方法。基本列表切片涉及用两个以冒号分隔的整数索引列表。

列表切片返回一个包含索引之间旧列表中所有值的新列表。

1
2
3
4
5
6
7
8
squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares[2:6])
print(squares[3:8])
print(squares[0:1])
结果:
[4, 9, 16, 25]
[9, 16, 25, 36, 49]
[0]

和Range参数一样,在一个 slice 中提供的第一个索引被包含在结果中,但是第二个索引没有。

如果省略了切片中的第一个数字,则将从列表第一个元素开始。

如果第二个数字被省略,则认为是到列表结束。

1
2
3
4
5
6
squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares[:7])
print(squares[7:])
结果:
[0, 1, 4, 9, 16, 25, 36]
[49, 64, 81]

切片也可以在元组上使用。

列表切片还可以有第三个数字,表示间隔。

1
2
3
4
5
6
7
8
squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares[::2])
print(squares[2:8:3])
结果:
[0, 4, 16, 36, 64]
[4, 25]

[2:8:3] 包含从索引2到8间隔3的元素。

负值也可用于列表切片(和正常列表索引)。当切片(或普通索引)中的第一个和第二个值使用负值时,它们将从列表的末尾算起。

1
2
3
4
5
6
7
8
9
10
11
12
squares = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares[1:-1])
print(squares[-3:-1])
print(squares[::-1])
结果:
[1, 4, 9, 16, 25, 36, 49, 64]
[49, 64]
[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]

sqs = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(sqs[7:5:-1])
[49, 36]

如果切片第三个数值使用负值,则切片进行逆序截取。
使用[::-1]作为切片是反转列表的常用方法。

12,字符串格式化

到目前为止,要组合字符串和非字符串,将非字符串转换为字符串并添加它们。

字符串格式化提供了一种更强大的方法来在字符串中嵌入非字符串。字符串格式化使用字符串的 format 方法来替换字符串中的多个参数。

例如:

1
2
3
4
5
6
# string formatting
nums = [4, 5, 6]
msg = "Numbers: {0} {1} {2}". format(nums[0], nums[1], nums[2])
print(msg)
结果:
Numbers: 4 5 6

format 函数的每个参数都放在相应位置的字符串中,这个位置是用花括号{}确定的。

字符串格式化也可以使用命名参数完成。、

1
2
3
4
a = "{x}, {y}".format(x=5, y=12)
print(a)
结果:
5,12

字符串格式化总结

总结:

1、按照默认顺序,不指定位置

1
2
3
print("{} {}".format("hello","world") )

hello world

2、设置指定位置,可以多次使用

1
2
3
print("{0} {1} {0}".format("hello","or"))

hello or hello

3、使用列表格式化

1
2
3
4
5
person = {"name":"W3Cschool","age":5}

print("My name is {name} . I am {age} years old .".format(**person))

My name is W3Cschool . I am 5 years old .

4、通过列表格式化

1
2
3
4
5
stu = ["W3Cschool","linux","MySQL","Python"]

print("My name is {0[0]} , I love {0[1]} !".format(stu))

My name is W3Cschool , I love linux !

字符串函数转换大小写

Python 包含许多有用的内置函数和方法来完成常见的任务。

join - 以另一个字符串作为分隔符连接字符串列表。

replace - 用另一个替换字符串中的一个子字符串。

startswith 和 endswith - 确定是否在字符串的开始和结尾处有一个子字符串。

要更改字符串的大小写,可以使用 lowerupper

split 方法与 join 相反,把一个字符串转换成一个列表。

**title()**每个单词的首字母大写

center(width, fillchar) 返回指定宽度的居中字符串,fillchar为填充的字符,默认是空格填充

**ljust(40,fillchar)**返回指定字符的左对齐

rjust(width,fillchar) 返回字符的右对齐

count(str[, start][, end]) #返回字符串中str出现的次数,可以指定一个范围,默认从头到尾

lstrip() 截掉字符串左侧指定的字符,默认为空格

rstrip() 截掉字符串右侧指定的字符,默认为空格

**strip()**截掉字符串左右两侧的指定字符,默认为空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
print(", ".join(["spam", "eggs", "ham"]))
#打印 "spam, eggs, ham"
print("Hello ME".replace("ME", "world"))
#打印 "Hello world"
print("This is a sentence.".startswith("This"))
# 打印 "True"
print("This is a sentence.".endswith("sentence."))
# 打印 "True"
print("This is a sentence.".upper())
# 打印 "THIS IS A SENTENCE."
print("AN ALL CAPS SENTENCE".lower())
#打印 "an all caps sentence"
print("spam, eggs, ham".split(", ")) #以,为分隔符,
#打印 "['spam', 'eggs', 'ham']"
qq = "30844875@qq.com"
lei= qq.split("@")[1].split(".")[0] #把QQ邮箱转成列表,取值下标指定的参数
#打印 qq 类型的邮箱

str1 = "sunck is a good man"
print(str1.title())
#打印 Sunck Is A Good Man
print(str1.center(40, "-"))
#打印 ----------sunck is a good man-----------

结果:

1
2
3
4
5
6
7
8
9
spam, eggs, ham
Hello world
True
True
THIS IS A SENTENCE.
an all caps sentence
['spam', 'eggs', 'ham']
Sunck Is A Good Man
----------sunck is a good man-----------

数字函数

要查找某些数字或列表的最大值或最小值,可以使用 maxmin

要将数字转成绝对值(该数字与0的距离),请使用 abs

要将数字四舍五入到一定的小数位数,请使用 round

要计算一个列表数字的总和,请使用 sum

求x的y次方 2^5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
print(min(1, 6, 3, 4, 0, 7, 1))
print(max([1, 2, 9, 2, 4, 7, 8]))
print(abs(-93))
print(round(3.456))
print(round(2.456, 2))
print(abs(22))
print(sum([1, 2, 3, 4, 5, 6]))
print(pow(2, 5))
结果:
0
9
93
3
3.46
22
21
32

列表函数

allany 将列表作为参数, 通常在条件语句中使用。

all 列表中所有值均为 True 时,结果为 True,否则结果为 False。

any 列表中只要有一个为 True,结果为 True,反之结果为 False。

enumerate 函数可以用来同时迭代列表的键和值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
nums = [55, 44, 33, 22, 11]

if all([i > 5 for i in nums]):
print("All larger than 5")

if any([i % 2 == 0 for i in nums]):
print("At least one is even")

for v in enumerate(nums):
print(v)
结果:
All larger than 5
At least one is even
(0, 55)
(1, 44)
(2, 33)
(3, 22)
(4, 11)

文本分析

这是一个示例项目,展示了一个分析示例文件以查找每个字符占用的文本百分比的程序。

1
2
3
4
5
6
filename = input("输入一个文件名: ")

with open(filename) as f:
text = f.read()

print(text)

程序的下一部分将查找每个字母占据文本的百分比。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def count_char(text, char):
count = 0
for c in text: #2,循环打开的文件内容
if c == char: #3,内容有等于char 则输出0+1次,出现多次就再加1
count += 1
return count #4,最终返回出现的总数

filename = input("输入一个文件名: ")
with open(filename) as f:
text = f.read()

print(count_char(text, "r")) #1,输出文件名,text ==文件名


for char in "abcdefghijklmnopqrstuvwxyz":
perc = 100 * count_char(text, char) / len(text)
print("{0} - {1}%".format(char, round(perc, 2)))

12, os模块

os: 包含了普遍的操作系统的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import os 

print(os.name) # 获取操作系统类型
结果:
nt windows系统
posix Linux、Unix或者Mac os x系统

print(os.uname()) #获取系统详细信息,posix系统类型上可以支持
posix.uname_result(sysname='Linux', nodename='server1.com', release='3.10.0-693.el7.x86_64', version='#1 SMP Tue Aug 22 21:09:27 UTC 2017', machine='x86_64')

print(os.environ) #获取操作系统中的所有环境变量
print(os.environ.get("pythonpath")) #获取指定环境变量
print(os.curdir) #获取当前路径
print(os.getcwd) #获取当前工作目录,即当前python脚本所在的目录,绝对路径
print(os.listdir(r"d:\py_work")) #以列表的形式获取指定目录下的文件列表 默认是当前脚本目录下的文件列表
os.mkdir(r"d:\py_work\newdir") # 在指定目录下创建目录。默认是在当前目录下创建
os.rmdir(r"d:\py_work\newdir) # 在指定目录下删除目录
print(os.stat("newdir")) #获取文件属性
os.rename("newdir","kaige") #重命名,把newdir重命名为kaige
os.remove("file.txt") #删除普通文件
os.system("notepad") #运行shell命令 需要执行什么就直接输入参数里就可以了
os.system("taskkill /f /im notepad.exe") #关闭某个程序。
os.system("write") #写字板
os.system("shutdown -s -t 60") #设置关机60秒后
os.system("shutdown -a") #计划的关机取消
print(os.path.abspath(".")) #查看当前目录的绝对路径
#拼接路径
p1 = r"d:\py_work"
p2 = "newdir"
print(os.path.join(p1,p2)) #注意: 参数2里的开始不要有斜杠
结果:
d:\py_work\newdir

#拆分路径 拆分最后一个
path2 = r"d:\py_work\newdir"
print(os.path.split(path2))
结果:
('d:\\py_work', 'newdir')
#获取扩展名
path2 = r"d:\py_work\newdir\test.txt"
print(os.path.splitext(path2))
结果:
('d:\\py_work\\newdir\\test', '.txt')
#判断是否是目录
print(os.path.isdir(path2))
结果:Falsh

#判断文件是否存在
print(os.path.isfile(path2))
结果:
True

#判断目录是否存在
print(os.path.exists(path2))

# 判断文件大小,以字节来算
print(os.path.getsize(path2))

#获取目录名
print(os.path.dirname(path2))
print(os.path.basename(path2))

13,窗口控制

需要下载模块 pip install pywin32

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import win32con
import win32gui
import time

#找出窗体的编号

QQWin = win32gui.FindWindow("TXGuiFoundation","QQ")

#隐藏窗口
win32gui.ShowWindow(QQWin,win32con.SW_HIDE)

time.sleep(2)
#显示窗体
win32gui.ShowWindow(QQWin,win32con.SW_SHOW)

#循环隐藏和显示窗口
while True:
win32gui.ShowWindow(QQWin, win32con.SW_HIDE)
time.sleep(1)
win32gui.ShowWindow(QQWin, win32con.SW_SHOW)
time.sleep(1)

2,控制窗体的位置和大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import win32con
import win32gui
import time
import random


#QQWin = win32gui.FindWindow("TXGuiFoundation","QQ")

#参数1:控制的窗体
#参数2:大致方位,HWND_TOPMOST上方
#参数3:位置x
#参数4:位置y
#参数5:长度
#参数6:宽度

#控制窗口随机乱动
while True:
QQWin = win32gui.FindWindow("TXGuiFoundation", "QQ")
x = random.randrange(900)
y = random.randrange(600)
win32gui.SetWindowPos(QQWin,win32con.HWND_TOPMOST,x,y,300,300,win32con.SWP_SHOWWINDOW)

#通过cmd启动脚本,后台运行 start /b python 1控制窗口.py

3,语音控制

1,一个简单的语音模仿程序

语音合成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#系统客户端
import win32com.client
import time


print("输入退出或者quit可以退出")
dehua = win32com.client.Dispatch("SAPI.SPVOICE")
luke ="这是逸尘写的小程序,欢迎测试哦"

dehua.Speak(luke)
time.sleep(0.5)
dehua.Speak("你输入什么。我就语音读什么")
dehua.Speak("请输入吧!")
while True:
hua =input("请输入 ")
if hua == "退出" or hua == "quit":
print("你退出了")
break
dehua.Speak(hua)

2,speech语音模块

模块简介

当我们想在windows平台上利用Python将文本转化为语音输出,用作语音提示,这时就要用到speech模块。该模块的主要功能有:语音识别、将指定文本合成语音以及语音信号输出等。

下载

用pip命令:pip install speech

另外,该模块以pywin32作为支撑,需要先下载pywin32模块,pywin32是一款Python Win32增强工具,可以方便得使用Python调用WIN32COM接口。可以在这个网站找到适合你系统的pywin32安装包下载安装:https://sourceforge.net/projects/pywin32/files/pywin32/

导入

import speech

修改

当我们使用python3调用speech会报错,需要手工修改speech.py程序:

line59 修改 import thread –> import threading

line157 修改 print prompt –> print(prompt)

示列代码

1
2
3
4
5
6
7
8
# 将输入文字转化为语音信号输出
import speech

while True:
speech.say("请输入:")
str = input("请输入:")
speech.say("你输入的内容是: ")
speech.say(str)

22,内存修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#进程模块
import win32process
#系统
import win32con
import win32gui
import win32api
import ctypes

PROCESS_ALL_ACCESS =(0x000F0000|0x0010000|0xFFF)
#找窗体
win = win32gui.FindWindow("MainWindow","植物大战僵尸中文版")
#根据窗体找到进程号
hid, pid = win32process.GetWindowThreadProcessId(win)
#以最高权限打开进程
p = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)

data = ctypes.c_long()
#加载内涵模块
md = ctypes.windll.LoadLibrary(r"‪C:\Windows\System32\KernelBase.dll")
#读取内存
md.ReadProcessMemory(int(p), 311944712,ctypes.byref(data), 4 , None)
print("data =", data)
#新值
newData = ctypes.c_long(10000)
#修改
md.WriteProcessMemory(int(p), 311944712, ctypes.byref(newData), 4 , None)

二,python3进阶知识重点

1,函数式编程

函数式编程是一种编程风格(顾名思义)是基于函数的。

函数式编程的关键部分是高阶函数。在上一课中,我们已经将这个想法简单地看作是对象的功能。高阶函数将其他函数作为参数,或将其作为结果返回。

例如:

1
2
3
4
5
6
7
8
9
10
11
def apply_twice(func, arg):   #func= add_five了,
return func(func(arg)) # 返回 +5(+5(10))== 5+(5+(10))

def add_five(x):
return x + 5 #如果改成x * 5 的话, 结果就会变成*5(*5(10))= 250了

print(apply_twice(add_five, 10))
结果:
20

函数 apply_twice 将另一个函数作为参数,并在其内部调用两次。

1,纯函数

函数式编程试图使用纯函数。纯函数没有副作用,并且返回一个仅依赖于它们的参数的值。

这是数学工作中的函数:例如,对于相同的 x,cos(x) 总是返回相同的结果。

纯函数的例子:

1
2
3
def pure_function(x, y):
temp = x + 2*y
return temp / (2*x + y)

非纯函数的例子:

1
2
3
4
5
6
some_list = []

def impure(arg):
some_list.append(arg)

上面的函数不是纯函数,因为它改变了 some_list 的状态。

纯函数优点和缺点。

纯函数具备:

- 更容易推理和测试。

- 更高效。

一旦函数有一个输入,结果可以被存储并在下一次需要该输入的函数时被引用,从而减少函数被调用的次数。

- 更容易并行运行。

仅使用纯函数的主要缺点是它们主要使 I/O 的其他简单任务复杂化。

在某些情况下,他们也可能更难编写。

2, Lambda 表达式

正常创建一个函数(使用 def)会自动将其分配给一个变量。

这与其他对象(如字符串和整数)的创建不同,它们可以在运行中创建,而不必将其分配给变量。

使用 lambda 语法创建函数。这种方式创建的函数被称为匿名函数

将一个简单函数作为参数传递给另一个函数时,这种方法是最常用的。

语法如下:

1
lambda 参数列表: 表达式
1
2
3
4
def my_func(f, arg):
return f(arg)

my_func(lambda x: 2*x*x, 5) # x表示参数

Lambda 函数从 lambon 演算中得名,这是 Alonzo Church 发明的计算模型。

Lambda 函数不如命名函数强大。

他们只能做需要单一表达的事情 - 通常相当于一行代码。

例如:

1
2
3
4
5
6
7
#命名函数
def polynomial(x):
return x**2 + 5*x + 4
print(polynomial(-4))

#lambda
print((lambda x: x**2 + 5*x + 4) (-4)) #-4的平方16 +(-20)+4=0

可以将 Lambda 函数分配给变量,并像普通函数一样使用。

例如:

1
2
3
4
5
6
double = lambda x: x * 2
print(double(7))
结果:
14

但是,很少这样做 - 用 def 定义一个函数通常会更好。

3, map和filter 函数

内置的函数 mapfilter 是在列表(或类似的称为迭代的对象)上运行的非常有用的高阶函数。

函数 map 接受一个函数和一个迭代器作为参数,并返回一个新的迭代器,该函数应用于每个参数。

例如:

1
2
3
4
5
6
7
8
def add_five(x):
return x + 5

nums = [11, 22, 33, 44, 55]
result = list(map(add_five, nums))
print(result)
结果:
[16, 27, 38, 49, 60]

通过使用 lambda 语法,我们可以更容易地获得相同的结果。

1
2
3
4
5
nums = [11, 22, 33, 44, 55]

result = list(map(lambda x: x+5, nums))
print(result)
为了将结果转换成列表,我们使用了 list 函数。

filter 函数通过删除与谓词(一个返回布尔值的函数)不匹配的项来过滤一个迭代。

语法:

1
filter(function, iterable)
  • function – 判断函数。
  • iterable – 可迭代对象

下面我们通过一个实例来说明:

1
2
3
4
5
nums = [11, 22, 33, 44, 55]
res = list(filter(lambda x: x%2==0, nums)) #可以匹配偶数的结果就打印出来
print(res)
结果:
[22,44]

与 map 一样,如果要打印结果,必须将结果显式转换为列表。

4,生成器

生成器是一种可迭代的类型,如列表或元组。

与列表不同的是,它们不允许使用任意索引,但是它们仍然可以通过 for 循环迭代。

可以使用 函数yield 语句来创建它们。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def countdown():
i=5
while i > 0:
yield i
i -= 1

for i in countdown():
print(i)
结果:
5
4
3
2
1

yield 语句用于定义一个生成器,替换函数的返回值以向调用者提供结果而不破坏局部变量。

6 内建模块 itertools

itertools 模块是一个标准库,包含了几个在函数式编程中很有用的函数。

一种类型的函数是无限迭代器。

count 函数从一个值无限增加。

cycle 函数无限次迭代(例如列表或字符串)。

repeat 函数重复一个对象,无论是无限还是特定的次数。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from itertools import count

for i in count(3):
print(i)
if i >=11:
break
结果:
3 #从3开始无限增加,一直到11为止
4
5
6
7
8
9
10
11

itertools 中有许多功能可以在迭代器上运行,类似于映射和过滤。

例如:

takewhile - 当判定函数(返回值为 True 或 False)保持为True时,从迭代中取得项目;

chain - 将几个迭代结合成一个长整数;

accumulate - 以可迭代的方式返回一个正在运行的值。

1
2
3
4
5
6
7
8
from itertools import accumulate, takewhile

nums = list(accumulate(range(8)))
print(nums)
print(list(takewhile(lambda x: x<= 6, nums)))
结果:
[0, 1, 3, 6, 10, 15, 21, 28] #0+0=0,0+1=1,1+2=3,3+3=6,6+4=10,10+5=15,15+6=21,21+7=28,0-7范围
[0, 1, 3, 6]

itertool中还有几个组合函数,比如 productpermutation。

当你想用一些项目的所有可能的组合来完成任务时使用。

例如:

1
2
3
4
5
from itertools import product, permutations

letters = ("A", "B")
print(list(product(letters, range(2)))) # 输出0-1和AB的各种组合
print(list(permutations(letters))) #输出AB的各种可能的组合

结果:

1
2
[('A', 0), ('A', 1), ('B', 0), ('B', 1)]  
[('A', 'B'), ('B', 'A')]

小节练习

1
2
3
4
5
6
7
8
9
10
11
12
13
def power(x, y):
if y == 0:
return 1
else:
return x * power(x, y-1)

print(power(3, 3)) # 3* power(3,2) 3*3*3

结果:
27

print(power(3, 4)) #输出 3* power(3,3) 3*3*3*3
结果:81

7,装饰器

装饰器 是修改其他函数的功能的函数。装饰器有助于让我们的代码更简短。

当您需要扩展您不想修改的函数功能时,这是很理想的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def outer(func):
def inner():
print("============")
func()
print("============")
return inner

def func1():
print("Hello world!")

f = outer(func1)
f()
结果:
============
Hello world!
============

我们定义了一个名为 outer的函数,它有一个单一的参数 func。

在 outer 中,我们定义了一个名为 inner的嵌套函数。

inner函数将打印一个字符串,然后调用 func(),并打印另一个字符串。

我们可以说,装饰变量是 func1的装饰版本 - 它是 func1加上一些东西。

这是通过重新赋值包含我们的函数的变量来完成的:

1
2
func1 = outer(func1)
func1()

这个模式可以随时用来包装任何功能。

Python通过预先用装饰器名称和 @symbol 预定义函数定义来提供支持,以便在装饰器中包装函数。

如果我们正在定义一个函数,我们可以使用@符号来“装饰”它:

1
2
3
4
5
6
7
8
9
10
11
12
def outer(func):
def inner():
print("============")
func()
print("============")
return inner

@outer
def func1():
print("Hello world!")

func1()

这将与上面的代码具有相同的结果。

第二个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def outer(func):
def inner(*args, **kwargs):
#添加修改的功能
print("&&&&&&&&&&")
func(*args, **kwargs)
return inner

@outer #写了这句就可以省略say = outer(say) 了。

def say(name, age): # 函数的参数理论上是无限的,但是实际上最好不要超过6,7个
print("my name is %s, I am %d years old " %(name, age))

#say = outer(say)

say("luke", 18)

一个函数可以有多个装饰器。

8,递归

递归调用: 一个函数,调用了自身,称为递归调用

递归函数: 一个会调用自身的函数称为递归函数

凡是循环能干的是,递归都能干

方式

  1. 写出临界条件

  2. 找这一次和上一次的关系

  3. 假设当前函数已经能用,调用自身计算上一次的结果,再求出本次的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#输入一个数(大于等于1),求1+2+3+.....+n的和
def sum1(n):
sum = 0
for x in range(1, n +1):
sum += x
return sum

res = sum1(5)

print("res =",res)

#递归函数
def sum2(n):
if n == 1: #临界条件
return 1
else:
return n + sum2(n - 1)
res = sum2(5)
print("res =",res)
结果都是15

'''
5 + sum2(4)
5 + 4 + sum2(3)
5 + 4 +3 + sum2(2)
5 + 4+ 3+ 2 + sum2(1)
5 + 4 + 3 + 2 + 1 等于返回15
'''

9.栈与队列 (循环的处理一些事情)

栈结构 先进后出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 模拟栈结构
stack = []

#压栈(向栈里存数据)
stack.append("A")
print(stack)
stack.append("B")
print(stack)
stack.append("C")
print(stack)

#出栈(在栈里取数据)
res1 = stack.pop()
print("res1 =", res1)
print(stack)

res2 = stack.pop()
print("res2 = ", res2)
print(stack)

res3 = stack.pop()
print("res3 = ", res3)
print(stack)

队列 先进先出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import collections

#创建一个队列
queue = collections.deque()
print(queue)

#进队(存数据)
queue.append("A")
print(queue)
queue.append("B")
print(queue)
queue.append("C")
print(queue)

#出队(取数据)
res1 = queue.popleft()
print("res1 = ", res1)
print(queue)
res2 = queue.popleft()
print("res2 = ", res2)
print(queue)
res3 = queue.popleft()
print("res3 = ", res3)
print(queue)

10,目录遍历

递归遍历目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os

def getAllDir(path, sp = ""):
#得到当前目录下的所有文件
filesList = os.listdir(path)

#处理每一个文件
sp = sp + " "
for fileName in filesList:
#判断是否是路径(用绝对路径)
fileAbsPath = os.path.join(path,fileName)
if os.path.isdir(fileAbsPath):
print(sp +"目录:", fileName)
#递归调用
getAllDir(fileAbsPath ,sp)
else:
print(sp +"普通文件:", fileName)

getAllDir(r"d:\py_work")

栈模拟递归遍历 目录(深度遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import os

def getAllDirDE(path):
stack = []
stack.append(path)

#处理栈,当栈为空的时候结束循环
while len(stack) != 0:

#从栈里取出数据,这里就等于拿到了绝对路径
dirPath = stack.pop()
#print(dirPath)
#目录下的所有文件
filesList = os.listdir(dirPath)
#处理每一个文件,如果是普通文件则打印出来,如果是目录则将该目录的地址压栈
for fileName in filesList:
fileAbsPath = os.path.join(dirPath,fileName)
if os.path.isdir(fileAbsPath): #判断是不是目录,
#是目录就压栈
print("目录:" + fileName) #输出目录名["B"]

stack.append(fileAbsPath) #再进行压栈,放入目录,再while循环判断

else:
#打印普通文件
print("文件:"+ fileName)

getAllDirDE(r"d:\py_work")

队列模拟递归遍历(广度遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import os
import collections

def getAllDirQU(path):
queue = collections.deque()
#进队
queue.append(path)

while len(queue) != 0:
#出队数据
dirPath = queue.popleft()
#找出所有的文件
filesList = os.listdir(dirPath)
for fileName in filesList:
#绝对路径
fileAbsPath = os.path.join(dirPath,fileName)
#是否是目录,是目录就进队,不是就打印
if os.path.isdir(fileAbsPath):
print("目录: " + fileName)
queue.append(fileAbsPath)
else:
print("普通文件:" + fileName)

getAllDirQU(r"d:\py_work")

2,时间模块

1,time模块

时间的表示形式:

1,时间戳

以整数或浮点型表示时间的一个以秒为单位的时间间隔,这个时间间隔的基础值是从1970年1月1日0点开始算起

2,元组

一种python的数据结构表示,这个元组有9个整数内容

1
2
3
4
5
6
7
8
9
10
属性                            值
tm_year(年) 比如2011
tm_mon(月) 1 - 12
tm_mday(日) 1 - 31
tm_hour(时) 0 - 23
tm_min(分) 0 - 59
tm_sec(秒) 0 - 61
tm_wday(weekday) 0 - 6(0表示周日)
tm_yday(一年中的第几天) 1 - 366
tm_isdst(是否是夏令时) 默认为-1

3,时间字符串格式结构

format time结构化表示

格式 含义
%a 本地(locale)简化星期名称
%A 本地完整星期名称
%b 本地简化月份名称
%B 本地完整月份名称
%c 本地相应的日期和时间表示
%d 一个月中的第几天(01 - 31)
%H 一天中的第几个小时(24小时制,00 - 23)
%I 第几个小时(12小时制,01 - 12)
%j 一年中的第几天(001 - 366)
%m 月份(01 - 12)
%M 分钟数(00 - 59)
%p 本地am或者pm的相应符
%S 秒(01 - 61)
%U 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。
%w 一个星期中的第几天(0 - 6,0是星期天)
%W 和%U基本相同,不同的是%W以星期一为一个星期的开始。
%x 本地相应日期
%X 本地相应时间
%y 去掉世纪的年份(00 - 99)
%Y 完整的年份
%Z 时区的名字(如果不存在为空字符)
%% ‘%’字符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import time

#返回当前时间的时间戳,浮点数形式,不需要参数
c = time.time()
print(c)

#将时间戳转为UTC时间元组
t = time.gmtime(c)
print(t)

#将时间戳转为本地时间元组
b = time.localtime(c)
print(b)

#将本地时间元组转成时间戳
m = time.mktime(b)
print(m)

#将时间元组转成字符串
s = time.asctime(b)
print(s)

#将时间戳转为字符串
p = time.ctime(c)
print(p)

#将时间元组转换成指定格式的字符串,参数2为时间元组,如果没有参数2,默认转当前时间
q = time.strftime("%Y-%m-%d %H:%M:%S", b)
print(q)
print(type(q))

#将时间字符串转为时间元组
w = time.strptime(q, "%Y-%m-%d %X")
print(w)

#延迟一个时间,整型或浮点型
#time.sleep(4)

#返回当前程序的cpu执行时间,Unix 始终返回全部的运行时间,windows从第二次开始,都是以第一个调用此函数
#开始的时间戳作为基数
y1 = time.clock() #python3.8已经弃用了。使用time.perf_counter()

y1 = time.perf_counter()

print(y1)

#测试cpu处理这个程序需要多少时间,可以测试性能。
time.perf_counter()
sum = 0
for i in range(100000000):
sum +=i

print(time.perf_counter())

常见结构化的时间组合:

1
2
print(time.strftime("%Y-%m-%d %X"))
#2020-05-11 06:15:53

time加减

1
2
3
4
5
6
7
import time

#timestamp加减单位以秒为单位
t1 = time.time()
t2 =t1 + 10
print(time.ctime(t1)) #Mon May 11 06:19:04 2020
print(time.ctime(t2)) #Mon May 11 06:19:14 2020

2.datetime日期时间模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import datetime

'''
datetime比time高级了不少,可以理解为datetime基于time进行了封装,提供了各种使用的函数,datetime模块的接口更直观,
更容易调用。

模块中的类:
datetime 同时有时间和日期
timedelta 主要用于计算时间的跨度
tzinfo 时区相关
time 只关注时间
date 只关注日期
'''

d1 = datetime.datetime.now()
print(d1)
print(type(d1))

#获取指定时间
d2 = datetime.datetime(1999,10,1, 10, 28, 25,123456)
print(d2)
#将时间转为字符串
d3 = d1.strftime("%Y-%m-%d %X")
print(d3)
print(type(d3))

#将格式化字符串转为datetime对象
#注意:转换的格式要与字符串一致
d4 = datetime.datetime.strptime(d3, "%Y-%m-%d %X" )
print(d4)

#做减法
d5 = datetime.datetime(1999,10,1, 10, 28, 25,123456)
d6 = datetime.datetime.now()
d7 = d6 - d5

print(d7)
print(type(d7))
#间隔的天数
print(d7.days)
#间隔天数除外的秒数
print(d7.seconds)

3,calendar日历模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import calendar


#使用
#输出指定年月份的日历
print(calendar.month(2019,8 ))

#返回指定年的日历
print(calendar.calendar(2019))
#可以判断闰年返回True,否则返回False
print(calendar.isleap(2000))
#返回某个月的周第一天,和总天数
print(calendar.monthrange(2019, 8))
#返回某个月以每一周为元素的列表
print(calendar.monthcalendar(2019,8))

3,面向对象编程

面向对象思想,指挥别人做事,

是一种符合人们思考习惯的思想

可以将复杂的事情简单化

将程序员从执行者转换成了指挥者

完成需求时:

​ 先要去找具有所需的功能的对象来用

​ 如果该对象不存在,那么创建一个具有所需功能的对象。

1,类

我们先前看过两种编程模式 - 命令式(使用语句,循环和函数)和 函数式(使用纯函数,高阶函数和递归)。

另一个非常流行的范例是面向对象编程(OOP)

对象是使用类来创建的,而这些类实际上是 OOP 的模具。

这个类(图纸设计)描述了这个对象是什么,但是和对象本身是分开的。换句话说,一个类可以被描述为一个对象的蓝图,描述或定义。

您可以使用相同的类作为创建多个不同对象的蓝图。

类的设计

只关心3样东西

​ 事物名称(类名):人(person)

​ 属性: 身高(height)、年龄(age)

​ 行为(功能): 跑(run)、打架(fight)

类是使用关键字 class 和一个包含类方法的缩进块创建的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
'''
设计类
类名:见名知意、首字母大写,其他遵守驼峰原则
属性: 见名知意、其他遵守驼峰原则
行为(方法/功能:)见名知意,其他遵循驼峰原则
'''
'''
创建类:
类:一种数据类型,本身并不占有内存空间,根据所学过的number,string,booleam等类似。用类创建实例话对象(变量).对象
占用内存空间

格式:
class 类名(父类列表):
属性
行为

'''
# object:基类,超类,所有类的父类,一般没有合适的父类就写object
class Person(object):
#定义属性(定义变量)
name = ""
age = 0
height = 0
weight = 0
#定义方法(定义函数)
#注意:方法的参数必须以self当第一个参数
#self代表类的实例(某个对象)
def run(self):
print("run")
def eat(self,food):
print("eat " + food)
def openDoor(self):
print("我已经打开了冰箱门")
def filleEle(self):
print("我已经把大象装进冰箱了")
def closeDoor(self):
print("我已经关闭了冰箱门")


'''
实例化对象
格式: 对象名 = 类名(参数列表) 对象名就是相当于变量名
注意: 没有参数,小括号也不能省略
'''
per1 = Person()
print(per1)
print(type(per1))
print(id(per1))
#都是同个类型,但不是同个人,不是同个对象。世上没有一模一样的对象。
per2 = Person()
print(per2)
print(type(per2))
print(id(per2))

'''
访问属性
格式:对象名.属性名
赋值: 对象名.属性名 = 新值
'''
per1.name = "tom"
per1.age = 18
per1.height = 160
per1.weight = 80
print(per1.name, per1.age , per1.height, per1.weight)

'''
访问方法(功能)
格式: 对象名.方法名(参数列表)

'''
#让这个对象去做动作,干活。
per1.openDoor()
per1.filleEle()
per1.closeDoor()

per1.eat("apple")

下面是一个简单的类和它的对象的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs
felix = Cat("ginger", 4)
rover = Cat("dog-colored", 4)
stumpy = Cat("brown", 3)

print("felix:",felix.__dict__) #dict是用来存储对象属性的一个字典,其键为属性名,值为属性的值.
print("rover:",rover.__dict__)
print("stumpy:",stumpy.__dict__)

结果:
felix: {'color': 'ginger', 'legs': 4}
rover: {'color': 'dog-colored', 'legs': 4}
stumpy: {'color': 'brown', 'legs': 3}

这段代码定义了一个名为 Cat 的类,它有两个属性:color 和 legs。
然后这个类被用来创建这个类的3个独立的对象.

__init__

__init__ 方法是一个类中最重要的方法。

这是在创建类的实例(对象)时使用类名称作为函数调用的。

所有的方法都必须以 self 作为自己的第一个参数,虽然它没有被明确地传递,但是 Python 为自己添加了自变量;

在调用方法时,不需要包含它。在一个方法定义中,self 指的是调用该方法的实例。self代表类的实例,也就是当前的对象。而非类,

1
2
3
哪个对象调用方法,那么该方法中的self就代表哪个对象 self中文是自己的意思,
self不是关键字。换成其他的标示符也可以,但是一般都是用self
self.__class__ 代表类名

注意: __init__ 是两个下划线, 不是一个下划线 _init_

类的实例具有属性,这些属性是与它们相关联的数据片段。

在这个例子中,Cat 实例具有属性 color 和 legs。这些可以通过在一个实例之后加一个点和属性名来访问。

__init__ 方法中,可以使用 self.attribute 来设置实例属性的初始值。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs

felix = Cat("ginger", 4)
print(felix.color)
print(felix.legs)

结果:
ginger
4
在上面的例子中,__init__ 方法接受两个参数并将它们分配给对象的属性。__init__ 方法被称为类构造函数。

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#           object:基类,超类,所有类的父类,一般没有合适的父类就写object
class Person(object):
#定义属性(定义变量)
name = ""
age = 0
height = 0
weight = 0
#定义方法(定义函数)
#注意:方法的参数必须以self当第一个参数
#self代表类的实例(某个对象)
def run(self):
print("run")
def eat(self,food):
print("eat " + food)

def __init__(self,name, age, height, weight):
#print(name, age, height, weight)
#定义属性
self.name = name
self.age = age
self.height = height
self.weight = weight
pass

'''
构造函数: __init__() 在使用类创建对象的时候自动调用
注意:如果不显示的写出构造函数,默认自动添加一个空的构造函数
'''
per = Person("hanmeimei", 20, 170, 55)
print(per.name, per.age)
per2 = Person("lilei", 21 ,175, 75)
print(per2.name,per2.age)

重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'''
重写:将函数重写定义写一遍

__str__():在调用print打印对象时自动调用,是给用户用的,是一个描述对象的方法
__repr__():是给机器用的,在Python解释器里面直接敲对象名在回车后调用的方法

注意: 在没有__str__时,且有__repr__, __str__=__repr__

优点:当一个对象的属性值比较多,并且都需要打印,重写了__str__方法后,简化了代码
'''


class Person(object):
def __init__(self,name, age, height,weight):
self.name = name
self.age = age
self.height = height
self.weight = weight

def __str__(self):
return "%s-%d-%d-%d" % (self.name,self.age,self.height, self.weight)


per = Person("hanmeimei", 20, 170, 55)
print(per)
输出:
hanmeimei-20-170-55

访问限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
'''
访问限制
'''


class Person(object):
def run(self):
print(self.__money)
print("run")
def eat(self,food):
print("eat " + food)

def __init__(self,name, age, height,weight,money):
self.name = name
self.age = age
self.height = height
self.weight = weight
self.__money = money #_Person__money

# 通过内部的方法,去修改私有属性
def setMoney(self,money):
if money < 0:
money = 0
self.__money = money
def getMoney(self):
return self.__money


per = Person("hanmeimei", 20, 170, 55,1000)
#per.age = 10
#print(per.age)

#如果要让内部的属性不被外部直接访问,在属性签加两个下划线(__),在python中,如果在属性前加两个下划线,那么这个属性就变成了私有属性。
#per.__money = 0
#print(per.__money) #外部使用,会报错
#per.run() #内部可以调用

per.setMoney(23) #通过内部方法,修改值为23
print(per.getMoney
结果:输出23,

#不能直接访问per.__money是因为python解释器把__money变成了_Person__moeny,但是强烈建议不要这么干,不同的解释器可能存在解释的变量不一致,

per._Person__money = 1 这样修改值就变成1
print(per.getMoney())

2,继承

继承提供了一种在类之间共享功能的方法。

想象几个类,Cat,Dog,Rabbit等。虽然它们在某些方面可能有所不同(只有 Dog 可能有 bark 方法),但它们可能在其他方面相似(都具有 color 和 name 的属性)。

这种相似性可以通过使它们全部从包含共享功能的超类 Animal 中继承来表示。

要从另一个类继承一个类,请将超类名放在类名后面的括号中。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Animal: 
def __init__(self, name, color):
self.name = name
self.color = color

class Cat(Animal):
def purr(self):
print("Purr...")

class Dog(Animal):
def bark(self):
print("Woof!")

fido = Dog("Fido", "brown")
print(fido.color)
fido.bark()
结果:
brown
woof!

从另一个类继承的类称为子类

被继承的类被称为超类。

如果一个类继承了另一个具有相同属性或方法的类,它的属性和方法将覆盖它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Wolf: 
def __init__(self, name, color):
self.name = name
self.color = color

def bark(self):
print("Grr...")

class Dog(Wolf):
def bark(self):
print("Woof")

husky = Dog("Max", "grey")
husky.bark()

结果:
woof
在上面的例子中,Wolf 是超类,Dog 是子类。

继承也可以是间接的。一个类B继承类A,而类C也可以继承类B。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A:
def method(self):
print("A method")

class B(A):
def another_method(self):
print("B method")

class C(B):
def third_method(self):
print("C method")

c = C()
c.method()
c.another_method()
c.third_method()

结果:
A method
B method
C method
但是,不允许循环继承。

super 函数是一个与父类继承相关的函数。它可以用来在对象的超类中找到具有特定名称的方法。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A:
def spam(self):
print(1)

class B(A):
def spam(self):
print(2)
super().spam()

B().spam()
结果:
2
1
super().spam() 是调用超类的 spam 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age

def run(self):
print("run")

def eat(self, food):
print("eat " + food)

class Student(Person):
def __init__(self, name,age,stuId):
#调用父类中的__init__
super(Student, self).__init__(name, age)
#子类可以有一些自己独有的属性
self.stuId = stuId

class Worker(Person):
def __init__(self, name,age):
#调用父类中的__init__, (worker,self)可以不用写
super(Worker, self).__init__(name, age)

stu = Student("tom" ,18 ,2)
print(stu.name,stu.age,stu.stuId )

wor = Worker("lilei", "20")
print(wor.name, wor.age )
wor.eat("apple")

多继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Father(object):
def __init__(self, money):
self.money = money
def play(self):
print("play")
def func (self):
print("func1")

class Mother(object):
def __init__(self, faveValue):
self.faceValue = faveValue
def eat(self):
print("eat")
def func(self):
print(func2)

#Father在前面
class Child(Father,Mother):
def __init__(self,money, faceValue):
#多继承的写法
Father.__init__(self, money)
Mother.__init__(self, faceValue)

#多继承的实现

def main():
c = Child(300, 100)
print(c.money, c.faceValue)
c.play()
c.eat()
#注意:父类中方法名相同,默认调用的是在括号中排前面的父类中的方法
c.func()
if __name__ == "__main__":
main()

多态

1
2
3
多态:一种事物的多种形态

最终目标:人可以喂任何一种动物

创建类人person.py

1
2
3
4
5
6
7
8
9
10
11
12
13
#人
class Person(object):
'''
def feedCat(self, cat):
print("给你食物")
cat.eat()
def feedMouse(self, mouse):
print("给你食物")
mouse.eat()
'''
def feedAnimal(self,ani):
print("给你食物")
ani.eat()

创建类动物 animal.py

1
2
3
4
5
6
#动物
class Animal(object):
def __init__(self, name):
self.name = name
def eat(self):
print(self.name + "吃")

创建类猫,老鼠cat.py ,mouse.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#猫
from animal import Animal

class Cat(Animal):
def __init__(self, name):
#self.name = name
super(Cat, self).__init__(name)

#老鼠
from animal import Animal

class Mouse(Animal):
def __init__(self, name):
#self.name = name
super(Mouse, self).__init__(name)

执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from cat import Cat
from mouse import Mouse
from person import Person

'''
多态:一种事物的多种形态

最终目标:人可以喂任何一种动物
'''
tom = Cat("tom")
jerry = Mouse("jerry")

tom.eat()
jerry.eat()

'''
思考:在添加100种动物,也都有name属性和eat方法
定义了一个有name属性和eat方法的Animal类, 让所有的动物类都继承自Animal

'''

#定义一个人类,可以喂猫和老鼠吃东西

per = Person()
#per.feedCat(tom)
#per.feedMouse(jerry)

#思考:人要喂100种动物,难道要写100个feed方法吗??
#tom和jerry都继承自动物

per.feedAnimal(tom)
per.feedAnimal(jerry)

动态添加属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from types import MethodType

#创建一个空类
class Person(object):
__slots__ = ("name", "age", "speak")

per = Person()
#动态添加属性,这体现了动态语言的特点(灵活)
per.name = "tom"

print(per.name)

#动态添加方法
def say(self):
print("my name is " + self.name)

per.speak = MethodType(say, per)
per.speak()
#思考:如果我们想要限制实例的属性怎么办?
#比如,只允许给对象添加name,age,height,weight属性

#解决:定义类的时候,定义一个特殊的属性( ),可以限制动态添加的属性
per.height = 170
#print(per.height)
print()

@property可以让你对受限制的访问的属性使用点.语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

class Person(object):
def __init__(self,age, name):
#属性直接对外暴露
#self.age = age
#限制访问
self.__age = age
self.__name = name
'''
def getAge(self):
return self.__age

def setAge(self, age):
if age < 0:
age = 0
self.__age = age
'''

@property
def age(self):
return self.__age
@age.setter #去掉下划线.setter
def age(self , age):
if age < 0:
age = 0
self.__age = age
@property
def name(self):
return self.__name
@name.setter #去掉下划线.setter
def name(self , name):
self.__name = name


per = Person(18,"tom")
#print(per.age)

#属性直接对外暴露
#不安全,没有数据的过滤
#per.age = -10
#print(per.age)
#使用限制访问,需要自己写set和get方法才能访问
#per.setAge(15)
#print(per.getAge())
per.age = 100 #相当于调用setAge
print(per.age) #相当于调用getAge
per.name = ("tom")
print(per.name)

3,魔术方法和操作符重载

魔术方法是在名称的开始和结尾都有双下划线的特殊方法。

到目前为止,我们唯一遇到的是 __init__,但还有其他几个。

它们被用来创建不能用普通方法表示的功能。

它们的一个常见用途是运算符重载

这意味着为自定义类定义运算符,允许使用 + 和 * 等运算符。

例子中魔术方法是 __add__ 重载 +。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)

first = Vector2D(5, 7)
second = Vector2D(3, 9)
result = first + second
print(result.x)
print(result.y)
结果:
8
16

__add__ 方法允许为我们的类中的 + 运算符定义自定义行为。
正如你所看到的,它添加了对象的相应属性并返回一个包含结果的新对象。
一旦定义了,我们就可以将这个类的两个对象相加。

魔术方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
常见的魔术方法: 

__sub__ 对应 -
__mul__ 对应 *
__truediv__ 对应 /
__floordiv__ 对应 //
__mod__ 对应 %
__pow__ 对应 **
__and__ 对应 &
__xor__ 对应 ^
__or__ 对应 |

表达式 x + y 被翻译成 x.__add__(y)。
然而,如果 x 没有实现 __add__,并且 x 和 y 的类型不同,则调用 y.__radd__(x)。
对于刚刚提到的所有魔法方法,都有等价的方法。

class SpecialString:
def __init__(self, cont):
self.cont = cont

def __truediv__(self, other):
line = "=" * len(other.cont)
return "\n".join([self.cont, line, other.cont])

spam = SpecialString("spam")
hello = SpecialString("Hello world!")
print(spam / hello)

结果:
spam
============
Hello world!

在上面的例子中,我们为我们的类 SpecialString 定义了除法操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Python 也为比较运算提供了魔术方法。

__lt__ 对应 <
__le__ 对应 <=
__eq__ 对应 ==
__ne__ 对应 !=
__gt__ 对应 >
__ge__ 对应 >=

如果 __ne__ 没有被实现,它将返回 __eq__ 相反的结果。

其他比较运算符之间没有其他关系。

例如:
class SpecialString:
def __init__(self, cont):
self.cont = cont

def __gt__(self, other):
for index in range(len(other.cont)+1):
result = other.cont[:index] + ">" + self.cont
result += ">" + other.cont[index:]
print(result)

spam = SpecialString("spam")
eggs = SpecialString("eggs")
spam > eggs

结果:
>spam>eggs
e>spam>ggs
eg>spam>gs
egg>spam>s
eggs>spam>
如您所见,您可以为重载操作符定义任何自定义行为
1
2
3
4
5
6
7
8
9
10
有几个神奇的方法使类像容器一样行事。

__len__ 对应 len()
__getitem__ 对应 获取索引
__setitem__ 对应 分配索引值
__delitem__ 对应 删除索引值
__iter__ 对应 迭代对象(例如for循环)
__contains__ 对应 in

还有很多其他的魔术方法,我们不会在这里介绍,比如将 __call__ 作为函数调用对象,__int__,__str__ 等等,将对象转换为内建类型。

4,正则表达式

1,介绍

Python 中的正则表达式可以使用 re 模块来访问,它是标准库的一部分。

定义正则表达式之后,可以使用 re.match 函数来确定字符串的开头是否匹配。

如果匹配,match 返回表示匹配的对象,否则返回 None。

为了避免在处理正则表达式时出现混淆,我们使用原始字符串 **r”expression”**。

原始字符串不会转义任何东西,这使得使用正则表达式更容易。

1
2
3
4
5
6
7
8
9
10
11
import re

pattern = r"spam"

if re.match(pattern, "spamspamspam"):
print("Match")
else:
print("No match")
结果:
match
上面的例子检查字符串是否匹配 "spam",如果是,则打印 "Match"。

其他的正则函数是 re.search 和 re.findall。

re.search 函数在字符串中的任何位置找到匹配的模式。

re.findall 函数返回一个与模式匹配的所有子串的列表。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import re

pattern = r"spam"

if re.match(pattern, "eggspamsausagespam"):
print("Match")
else:
print("No match")

if re.search(pattern, "eggspamsausagespam"):
print("Match")
else:
print("No match")

print(re.findall(pattern, "eggspamsausagespam"))
结果:
No match
Match
['spam', 'spam']

在上面的示例中,匹配函数与模式不匹配,因为它从字符串的开头开始匹配。
search 函数找到了匹配的字符串。

函数 re.finditer 和 re.findall 类似,不过它返回一个迭代器,而不是一个列表。

正则表达式搜索使用多个方法返回一个对象,提供有关它的详细信息。

这些方法包括返回匹配的字符串的组,返回第一个匹配的开始和结束位置的开始和结束,以及将第一个匹配的开始和结束位置作为元组返回的跨度。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

pattern = r"pam"

match = re.search(pattern, "eggspamsausage")
if match:
print(match.group())
print(match.start())
print(match.end())
print(match.span())
结果:
pam
4
7
(4, 7)

使用正则表达式的最重要的 re 方法是 sub。

语法:

re.sub(pattern, repl, string, max=0)

此方法用 repl 替换字符串中所有出现的模式,除非提供 max限定修改数量。

sub 方法返回修改后的字符串。

例如:

1
2
3
4
5
6
7
8
import re

str = "My name is Loen. Hi Loen."
pattern = r"Loen"
newstr = re.sub(pattern, "Amy", str) #str表示上面的变量
print(newstr)
结果:
My name is Amy. Hi Amy.

2,元字符

我们将看到的第一个元字符是 . (点)。

它匹配任何字符,但不匹配新的行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

pattern = r"gr.y"

if re.match(pattern, "grey"):
print("Match 1")

if re.match(pattern, "gray"):
print("Match 2")

if re.match(pattern, "blue"):
print("Match 3")
结果:
Match 1
Match 2

接下来的两个元字符是 ^$

这两个分别匹配字符串的开始和结束。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

pattern = r"^gr.y$"

if re.match(pattern, "grey"):
print("Match 1")

if re.match(pattern, "gray"):
print("Match 2")

if re.match(pattern, "stingray"):
print("Match 3")
结果:
Match 1
Match 2

模式 “^gr.y$” 表示字符串应该以gr开头,然后跟随一个任何字符,除了换行符,并以y结尾。

3,字符类

字符类提供了一种只匹配特定字符集中的一个的方法。

通过将匹配的字符放在方括号内来创建字符类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

pattern = r"[aeiou]"

if re.search(pattern, "grey"):
print("Match 1")

if re.search(pattern, "qwertyuiop"):
print("Match 2")

if re.search(pattern, "rhythm myths"):
print("Match 3")
结果:
match 1
match 2

搜索函数中的模式 [aeiou] 匹配包含任何一个定义的字符的所有字符串。

字符类也可以匹配字符的范围。

一些例子:

[a-z] 匹配任何小写字母字符。

[G-P] 匹配从 G 到 P 的任何大写字符。

[0-9] 匹配任何数字。

一个字符类可以包含多个范围。例如,**[A-Za-z]** 匹配任何一个字母。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import re

pattern = r"[A-Z][A-Z][0-9]"

if re.search(pattern, "LS8"):
print("Match 1")

if re.search(pattern, "E3"):
print("Match 2")

if re.search(pattern, "1ab"):
print("Match 3")

结果:
Match 1
上例中的模式匹配包含两个大写字母后跟一个数字的字符串。

在字符类的开头放置一个 ^ 来反转它, 这使得它匹配除包含的字符之外的任何字符。

其他元字符(如 $ 和 .)在字符类中没有意义。

元字符 ^ 没有意义,除非它是一个字符类中的第一个字符。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import re

pattern = r"[^A-Z]"

if re.search(pattern, "this is all quiet"):
print("Match 1")

if re.search(pattern, "AbCdEfG123"):
print("Match 2")

if re.search(pattern, "THISISALLSHOUTING"):
print("Match 3")
结果:
match 1
match 2
模式[^A-Z]匹配不包括大写字母的所有字符。

4,更多的元字符

更多的元字符 ***,+{** 和 }

这些指定了重复次数。

元字符 * 表示 “零次或者多次重复以前的事情”。它匹配尽可能多的重复。* 号前可以是一个单独的字符,一个类,或一组括在括号中的字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import re

pattern = r"egg(spam)*"

if re.match(pattern, "egg"):
print("Match 1")

if re.match(pattern, "eggspamspamegg"):
print("Match 2")

if re.match(pattern, "spam"):
print("Match 3")
结果:
Match 1
Match 2
上面的例子匹配以 "egg" 开头的字符串,并跟随零个或多个 "spam"。

元字符 +* 非常相似,不同之处在于 + 是 “一个或多个重复”,而 * 是“零个或多个重复”。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

pattern = r"g+"

if re.match(pattern, "g"):
print("Match 1")

if re.match(pattern, "gggggggggggggg"):
print("Match 2")

if re.match(pattern, "abc"):
print("Match 3")
结果:
Match 1
Match 2

总结:
* 匹配0个或更多的前面的表达式。
+ 匹配1个或更多的前面的表达式。

元字符 ? 匹配 “零重复或一次重复”。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re

pattern = r"ice(-)?cream"

if re.match(pattern, "ice-cream"):
print("Match 1")

if re.match(pattern, "icecream"):
print("Match 2")

if re.match(pattern, "sausages"):
print("Match 3")

if re.match(pattern, "ice--ice"):
print("Match 4")
结果:
match 1
match 2

大括号可以用来表示两个数字之间的重复次数。

正则表达式 {x,y} 表示 “在x和y之间重复某事”。

因此 {0, 1} 与 ? 相同。

大括号如果第一个数字缺失,则将其视为零。如果第二个数字丢失,则被认为是无限的。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import re

pattern = r"9{1,3}$"

if re.match(pattern, "9"):
print("Match 1")

if re.match(pattern, "999"):
print("Match 2")

if re.match(pattern, "9999"):
print("Match 3")
结果:
Match 1
Match 2

"9{1,3}$" 匹配具有1到3个9的字符串。

5,分组

可以通过用圆括号围绕正则表达式的一部分来创建组。

这意味着一个组可以作为元字符的参数,如 * 和?。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import re

pattern = r"egg(spam)*"

if re.match(pattern, "egg"):
print("Match 1")

if re.match(pattern, "eggspamspamspamegg"):
print("Match 2")

if re.match(pattern, "spam"):
print("Match 3")

(spam)代表上面示例模式中的一个组。
结果:
match 1
match 2

可以使用组功能访问匹配组中的内容。

可以调用 group(0) 或者 group() 返回整个匹配。

调用 group(n) ,n 要大于 0,返回匹配的第 n 个组。

groups() 返回所有匹配的分组。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re

pattern = r"a(bc)(de)(f(g)h)i"

match = re.match(pattern, "abcdefghijklmnop")
if match:
print(match.group())
print(match.group(0))
print(match.group(1))
print(match.group(2))
print(match.groups())
结果:
abcdefghi
abcdefghi
bc
de
('bc', 'de', 'fgh', 'g')
从上面的例子可以看出,组可以嵌套。

另一个重要的元字符是 |

意思是与,比如 red|blue 匹配 “red”或者”blue”。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re

pattern = r"gr(a|e)y"

match = re.match(pattern, "gray")
if match:
print ("Match 1")

match = re.match(pattern, "grey")
if match:
print ("Match 2")

match = re.match(pattern, "griy")
if match:
print ("Match 3")
结果:
match 1
match 2

更有用的特殊序列是 \d\s\w

这些分别匹配数字,空格和单词字符。

在 ASCII 模式下,它们相当于 [0-9],[\t \n \r \f \v] 和 [a-zA-Z0-9_]。

在 Unicode 模式下,它们也匹配某些其他字符,例如,\w 匹配带有重音的字母。

大写字母 - \D,\S 和 \W - 这些特殊序列的版本意味着与小写字母相反的版本,例如,\D 匹配任何不是数字的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re

pattern = r"(\D+\d)"

match = re.match(pattern, "Hi 999!")

if match:
print("Match 1")

match = re.match(pattern, "1, 23, 456!")
if match:
print("Match 2")

match = re.match(pattern, " ! $?")
if match:
print("Match 3")
结果:
Match 1

(\D+\d) 匹配一个或多个非数字后跟一个数字。

其他特殊序列是 \A\Z\b

序列 \A\Z 分别匹配字符串的开头和结尾。

序列 \b 匹配 \w\W 字符之间的空字符串,或 \w 字符和字符串的开始或结尾。非正式地,它代表了单词之间的界限。

序列 \B 匹配其他地方的空字符串。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import re

pattern = r"\b(cat)\b"

match = re.search(pattern, "The cat sat!")
if match:
print ("Match 1")

match = re.search(pattern, "We s>cat<tered?")
if match:
print ("Match 2")

match = re.search(pattern, "We scattered.")
if match:
print ("Match 3")

结果:
match 1
match 2
"\b(cat)\b" 基本上与单词边界包围的单词 "cat" 匹配。

5,__main__

如果我们将前一个示例的代码保存为 w3cschool.py 文件,则可以使用 w3cschool 名称将其作为模块导入到另一个脚本中。

w3cschool.py

1
2
3
4
5
def function():
print("This is a module function")

if __name__=="__main__":
print("This is a script")

some_script.py

1
2
3
4
5
import w3cschool

w3cschool.function()
结果:
This is a module function

6,打包

在 Python 中,术语打包指的是将模块写成标准格式,以便其他程序员可以轻松安装和使用它们。

为了解决模块命名的冲突,引入了按目录来组织模块的方法称为包,

特点,引入了包以后,只要顶层的包不与其他人发生冲突,那么模块都不会与别人的发生冲突。

这包括使用模块 setuptoolsdistutils

打包第一步是正确组织现有文件。将所有要放入库的文件放在同一个父目录中。

该目录还应该包含一个名为 __init__.py 的文件,该文件可以是空白的,但必须存在于目录中

示例目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
W3Cschool/
LICENSE.txt
README.txt
setup.py
w3c/
__init__.py
w3cschool.py
w3cschool2.py
您可以根据需要在目录中放置尽可能多的脚本文件

__init__.py 文件的作用是什么呢?

__init__.py 最明显的作用就是使包和普通目录区分;其次可以在该文件中申明模块级别的import语句从而使其变成包级别可见。
导入包格式是:
import w3c.w3cschool #w3c代表包名
import a.w3cschool #a代表包名

打包的下一步是编写 setup.py 文件。

这包含组装软件包所需的信息,以便将其上传到 PyPI 并使用 pip (名称,版本等)进行安装。

setup.py 文件的示例:

1
2
3
4
5
6
7
8
9
from distutils.core import setup

setup(
name='W3Cschool',
version='0.1dev',
packages=['w3cschool',],
license='MIT',
long_description=open('README.txt').read(),
)

创建 setup.py 文件后,将其上传到 PyPI,或使用命令行创建二进制分发(可执行安装程序)。

要构建源代码发行版,请使用命令行导航到包含 setup.py 的目录,然后运行 python setup.py sdist 命令。

运行 python setup.py bdist,或者对于Windows,使用 python setup.py bdist_wininst 来构建二进制分发。

使用 python setup.py register,然后用 python setup.py sdist upload 来上传一个包。

最后,用 python setup.py install 安装一个软件包。

为用户打包

上一课包含了供其他 Python 程序员使用的打包模块。但是,许多不是程序员的计算机用户没有安装 Python。

因此,将脚本打包为相关平台(如 Windows 或 Mac 操作系统)的可执行文件很有用。

这对于 Linux 来说不是必需的,因为大多数 Linux 用户的确已经安装了Python,并且能够像原来一样运行脚本。

对于 Windows,许多工具可用于将脚本转换为可执行文件。例如,py2exe 可用于将 Python 脚本及其所需的库打包到单个可执行文件中。

PyInstallercx_Freeze 服务于相同的目的。

Mac 使用 py2app,PyInstaller 或 cx_Freeze。

pyinstaller xxx.py

注:终端需切换至xxx.py文件所在目录下。

常用可选项及说明:

-F:打包后只生成单个exe格式文件;

-D:默认选项,创建一个目录,包含exe文件以及大量依赖文件;

-c:默认选项,使用控制台(就是类似cmd的黑框);

-w:不使用控制台;

-p:添加搜索路径,让其找到对应的库;

-i:改变生成程序的icon图标。

评论


:D 一言句子获取中...

加载中,最新评论有1分钟缓存...