目录
第一章 python语言基础
1.1 变量和简单数据类型
引言——“机器语言/汇编语言通过内存单元地址访问数据,高级语言通过内存单元名字访问,命名的内存单元称为变量。”
1.1.1 标识符
(1)不能以数字开头:标识符的第一个字符必须是字母(a-z或A-Z)或下划线(_),不能是数字。
(2)不能包含非法字符:标识符只能包含字母(a-z或A-Z)、数字(0-9)或下划线(_)。不能包含空格、特殊符号(如@、#、$、%等)或运算符(如+、-、*、/等)。
(3)数字不能作为标识符:标识符不能以数字开头,也不能全是数字。例如,
123
、4567
等都是不合法的标识符。(4)不能包含空格:标识符中不能包含空格。如果需要使用多个单词来表示一个标识符,可以使用下划线(_)来连接。
(5)不能包含运算符:标识符中不能包含运算符,如
+
、-
、*
、/
等。(6)不能是Python保留关键字:Python有一些保留关键字,如
def
、class
、if
、else
等,这些关键字不能作为标识符。
1.1.2 关键字
(1)查看关键字python代码:
import keyword # 调用keyword模块
print(keyword.kwlist)
print(len(keyword.kwlist))
(2)输出结果:
['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']
35
(3)部分关键字说明:
控制流程关键字:
if
,elif
,else
: 用于条件判断。for
,while
: 用于循环控制。break
,continue
: 用于跳出循环或跳过当前迭代。try
,except
,finally
: 用于异常处理。定义变量或常量关键字:
def
: 用于定义函数。class
: 用于定义类。lambda
: 用于定义匿名函数(lambda函数)。import
: 用于导入模块。from
: 与import
结合使用,用于从模块中导入特定的函数或变量。常量关键字:
True
,False
: 布尔类型的值,分别表示真和假。None
: 表示空值或没有值。特殊用途关键字:
and
,or
,not
: 逻辑运算符,用于组合或取反条件。as
: 用于指定别名,例如在导入模块或定义函数时。global
,nonlocal
: 用于声明变量的作用域。in
: 用于判断一个成员是否属于一个序列。is
: 用于判断两个对象是否相同。其他关键字:
async
,await
: 用于定义异步函数和异步上下文管理。del
: 用于删除变量或序列的值。pass
: 一个空操作,用于占位。return
: 用于从函数中返回一个值。raise
: 用于引发异常。with
: 用于简化资源管理的上下文管理器。yield
: 用于定义生成器函数。
1.1.3 下划线标识符
1.1.3 常量和变量
对象 | 说明 | 举例 |
---|---|---|
常量( 不可变对象) | 执行过程中,数值不变的量 | 3,-6,"csdn" |
变量(可变对象) | 变量是一个可以存储和引用数据的标识符。 | n=5,x="csdn" |
注意常量:Python语言只是约定,程序运行中不变的量就是常量,通常实用全部大写字母PI=3.14
1.2 基本数字类型
特别注意:使用 {}
创建的是一个空字典,而不是空集合。
emp={}
print(type(emp))
#输出结果:
#<class 'dict'>
Python 基本数据类型,大致分为以下三大类:
1. 数字类型
1) 整数(Integers):可以是正数或负数,不带小数点。
例如:
100
,-786
,0
。八进制:可以在数字前面加上
0o
或0O
(零和小写或大写的字母O)。十六进制:可以在数字前面加上
0x
或0X
(零和小写或大写的字母X)空类型:0
2)浮点数(Floating point numbers):带有小数点的数字。
例如:
15.20
,0.0
,-21.9
,32.3+e18
。空类型:0.0
3)复数(Complex Numbers):包含实部和虚部的数字。
例如:
3.14j
,45.j
, 9.322e-36j
。空类型:0,0.0,0j
4)布尔值(Boolean):有两个值,
True
和False
。对象判断的空类型均已标记,附加空对象None
2.字符串(String):由零个或多个字符组成的有序字符序列。
例如:
'Hello, World!'
。空类型:''
3.其他类型
1)列表(List):有序的集合,可以包含不同类型的元素。
例如:
[1, 'a', 2.3]
。空类型: []
2)元组(Tuple):不可变的序列类型,与列表类似,但一旦创建就不能修改。
例如:
(1, 'a', 2.3)
。空类型:()
3)集合(Set):无序且不包含重复元素的集合。例如:
{1, 2, 3}
。4)字典(Dictionary):无序的键值对集合。例如:
{'name': 'John', 'age': 30}
。空类型:{}
1.3 运算符和表达式
算术运算符
+
:加法-
:减法*
:乘法/
:除法//
:整除(返回商的整数部分)%
:取模(返回除法的余数)**
:幂运算(指数运算)
比较运算符
==
:等于!=
:不等于>
:大于<
:小于>=
:大于或等于<=
:小于或等于
逻辑运算符
and
:逻辑与or
:逻辑或not
:逻辑非
位运算符
&
:按位与|
:按位或^
:按位异或~
:按位取反<<
:左移>>
:右移
成员运算符
in
:如果元素在序列中则返回Truenot in
:如果元素不在序列中则返回True
身份运算符
is
:如果两个对象是同一个对象则返回Trueis not
:如果两个对象不是同一个对象则返回True
赋值运算符
=
:赋值+=
:加法赋值-=
:减法赋值*=
:乘法赋值/=
:除法赋值//=
:整除赋值%=
:取模赋值**=
:幂赋值
其他运算符
.
:对象属性访问->
:函数注解(类型提示)
1.4 顺序结构
1.4.1 赋值语句
在Python中,赋值语句有几种不同的赋值方法,包括基本的赋值、多重赋值、链式赋值、增量赋值以及解包赋值等。以下是这些方法的详细描述
1. 基本赋值:
这是最基本的赋值方法,其中等号=用于将一个值赋给一个变量。
x=10
多重赋值(同步赋值):
你可以在同一行中给多个变量赋值。
x,y,z=1,2,3
2. 链式赋值:
链式赋值允许你将同一个值赋给多个变量。
x=y=z=42
3. 增量赋值:
增量赋值运算符(如+=、-=、*=、/=、//=、%=、**=、<<=、>>=)用于将变量与其自身的某个操作结果相加(或相减、相乘等),然后将结果赋值回该变量。
x+=5#等价于x=x+5
y-=10#等价于y=y-10
z*=2#等价于z=z*2
4. 解包赋值:
解包赋值允许你将一个序列(如列表或元组)或字典的值解包并分别赋值给多个变量。
对于序列:
values=(1,2,3)
x,y,z=values
增强赋值:
除了增量赋值运算符外,Python还支持其他形式的增强赋值,如位运算赋值(&=、|=、^=)等。
x&=3#等价于x=x&3
y|=4#等价于y=y|4
z^=2#等价于z=z^2
1.4.2 输入输出
1. input(prompt)函数
在Python中,input()
函数的调用格式相对简单。它接受一个可选的字符串参数作为提示信息(prompt),用于在控制台中显示给用户,告诉用户应该输入什么内容。当用户看到提示信息并输入内容后,input()
函数会返回用户输入的字符串。
调用格式:
value = input([prompt])
value
是一个变量,用于存储用户输入的字符串。prompt
是一个可选的字符串参数,用于提示用户输入内容。如果提供了prompt
,它会在用户输入之前显示在控制台中。input()
函数不接受任何关键字参数。
2. print函数
在Python中,print()
函数用于输出信息到控制台。print()
函数的调用格式相对简单,可以接受多个参数,并将它们打印到标准输出设备(通常是终端或命令行界面)。
print()
函数的调用格式如下:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
参数说明:
*objects
: 这是一个可变参数,意味着你可以传入任意数量的参数,它们将被打印出来。这些参数可以是字符串、数字、变量等。sep
: 这是一个字符串参数,指定了多个参数之间的分隔符,默认为一个空格(' ')。end
: 这是一个字符串参数,指定了打印结束后添加的字符或字符串,默认为换行符('\n'),意味着每次调用print()
后都会开始新的一行。file
: 这是一个文件对象参数,指定了输出应该写入的文件,而不是标准输出。默认值是sys.stdout
,表示标准输出。flush
: 这是一个布尔值参数,指定是否立即刷新输出缓冲区。默认值为False
,意味着输出可能不会被立即显示,而是被缓冲起来,直到缓冲区满或遇到其他刷新条件。
1.5 分支结构
Python中的分支结构主要有三种类型:单分支结构、双分支结构(也称为二分支结构)和多分支结构。
1.单分支结构:这种结构使用if语句来检查某个条件是否为真。如果条件为真,则执行相应的代码块;如果条件为假,则跳过该代码块并执行后面的代码。
例如:
if age >= 18:
print("可以去网吧!")
2.双分支结构:这种结构使用if-else语句来检查某个条件。如果条件为真,则执行if后面的代码块;如果条件为假,则执行else后面的代码块。
例如:
if age >= 18:
print("可以去网吧!")
else:
print("不能去网吧。")
3.多分支结构:这种结构使用if-elif-else语句来检查多个条件。Python会按照if、elif、else的顺序逐个检查条件,一旦找到为真的条件,就执行相应的代码块,并跳过后面的条件检查。如果没有任何条件为真,则执行else后面的代码块(如果有的话)。
例如:
if age < 10:
print("儿童")
elif age < 18:
print("青少年")
else:
print("成年人")
1.6 循环结构
1.6.1 可迭代对象
可迭代对象就是:执行一次可以返回一个元素的对象。
Python 中的可迭代对象(Iterable)是指那些可以遍历其元素的对象。可迭代对象实现了 __iter__()
方法,该方法返回一个迭代器(Iterator)。迭代器实现了 __next__()
方法,用于遍历元素。
以下是一些常见的 Python 可迭代对象:
- 列表(List):例如
[1, 2, 3, 4, 5]
。 - 元组(Tuple):例如
(1, 2, 3, 4, 5)
。 - 字符串(String):例如
"hello"
。 - 字典(Dictionary):例如
{"a": 1, "b": 2}
。注意,虽然字典是可迭代的,但迭代时默认返回的是字典的键(keys)。 - 集合(Set):例如
{1, 2, 3, 4, 5}
。 - 自定义数据类型:你可以通过实现
__iter__()
方法来使自定义数据类型成为可迭代对象。 - 生成器(Generator):生成器是一种特殊的迭代器,使用
yield
关键字定义,可以按需生成值。 - 文件对象(File Object):当你打开一个文件时,返回的文件对象是可迭代的,可以按行迭代文件内容。
- range 对象:
range
函数返回的对象也是一个可迭代对象,用于生成一个数字序列。
代码如下:
# 列表
my_list = [1, 2, 3, 4, 5]
for item in my_list:
print(item)
# 元组
my_tuple = (1, 2, 3, 4, 5)
for item in my_Tuple:
print(item)
# 字符串
my_string = "hello"
for char in my_string:
print(char)
# 字典(默认迭代键)
my_dict = {"a": 1, "b": 2}
for key in my_dict:
print(key)
# 集合
my_set = {1, 2, 3, 4, 5}
for item in my_set:
print(item)
# range 对象
for i in range(5):
print(i)
# 文件对象(按行迭代)
with open("myfile.txt", "r") as file:
for line in file:
print(line.strip())
1.6.2 循环语句
Python中的循环语句用于重复执行一段代码,直到满足特定的条件为止。Python提供了几种不同类型的循环语句,包括for
循环和while
循环。
1. for
循环
for
循环用于遍历可迭代对象(如列表、元组、字符串、字典、集合等)的元素。
调用格式:
for 变量 in 序列或可迭代对象:
循环体
例如:
# 遍历列表
fruits = ['apple', 'banana', 'cherry']
for fruit in fruits:
print(fruit)
# 遍历字符串
for char in 'hello':
print(char)
# 遍历字典(默认遍历键)
dictionary = {'a': 1, 'b': 2, 'c': 3}
for key in dictionary:
print(key, dictionary[key])
# 遍历集合
my_set = {1, 2, 3, 4, 5}
for item in my_set:
print(item)
# 使用range()函数遍历数字序列
for i in range(5): # 从0到4
print(i)
# 使用enumerate()遍历列表的索引和值
fruits = ['apple', 'banana', 'cherry']
for index, fruit in enumerate(fruits):
print(index, fruit)
2. while
循环
while
循环用于在满足某个条件时重复执行一段代码。
调用格式:
while 判断条件:
循环体
# 当条件为真时,执行循环体
count = 0
while count < 5:
print(count)
count += 1 # 更新条件变量
# 使用break语句提前退出循环
count = 0
while True:
print(count)
if count >= 5:
break # 当count大于或等于5时,退出循环
count += 1
# 使用continue语句跳过当前循环的剩余部分
count = 0
while count < 10:
count += 1
if count % 2 == 0: # 如果是偶数
continue # 跳过此次循环
print(count) # 只打印奇数
1.6.3 循环控制语句
在Python中,循环控制语句用于在循环体内控制循环的流程和条件。除了之前提到的for
和while
循环外,还有几种常见的循环控制语句,包括break
、continue
和pass
。
break
语句
break
语句用于在循环中任何时候停止或终止循环。当break
语句被执行时,循环将立即停止,程序流程将继续在循环结构之后的第一条语句。
for i in range(10):
if i == 5:
break # 当i等于5时,退出循环
print(i)
continue
语句
continue
语句用于跳过当前循环迭代的剩余部分,并开始下一次迭代。当continue
语句被执行时,循环将跳过continue
之后的代码,直接进行下一次循环。
for i in range(10):
if i == 5:
continue # 当i等于5时,跳过本次循环
print(i)
pass
语句
pass
语句是一个空操作语句,当语法上需要一个语句,但程序不需要任何操作时,可以使用pass
。在循环中,你可以使用pass
来创建一个占位符,以便稍后添加代码。
for i in range(10):
if i == 5:
pass # 这里什么都不做,只是一个占位符
print(i)
第二章 基础数据结构
小提示:此处是我们经常要用的地方,是数据结构的部分内容,接下来讲的这类数据结构统称容器
2.1 列表常用方法
2.2 元组
我们可以将其看作不可修改的列表,需要注意的是当元组只有一个元素时,需要在第一个元素后添加逗号。
需要注意的是,由于元组是不可变的,因此它们没有像列表那样的append
、extend
、insert
、remove
、pop
、clear
、sort
和reverse
等方法。
2.3 字典
需要注意的是,字典方法和函数通常不会返回字典本身(除非特别指明,如copy()
方法),而是返回其他数据类型(如列表、元组等)或执行某些操作(如修改字典内容)。
此外,字典还支持一些内置操作,如使用len(dict)
来获取字典的长度(即键值对的数量),以及使用key in dict
来检查一个键是否存在于字典中。
2.4 小结创建空的数据容器
列表(List):
empty_list = []
元组(Tuple):
empty_tuple = (None,)
字典(Dictionary):
empty_tuple = tuple()
集合(Set):
empty_set = set()
第三章 函数与模块
3.1 函数的定义与调用
3.1.1 函数定义
def function_name(parameters):
"""This is a docstring."""
# 函数体,包含一系列执行特定任务的语句
# 可以使用参数(parameters)来传递数据到函数内部
# 函数可以包含返回语句(return),用于返回一个值
return value
def
:这是定义函数的关键字。function_name
:这是函数的名称,用于在代码中调用该函数。parameters
:这是函数的参数列表,用于传递数据到函数内部。参数是可选的,也就是说,函数可以不接受任何参数。"""This is a docstring."""
:这是一个可选的文档字符串(docstring),用于解释函数的目的和行为。return value
:这也是可选的,用于指定函数执行后返回的值。如果函数没有return
语句,或者return
语句没有跟任何值,则函数返回None
。- 定义函数命名以“:”结尾,然后另起一行写函数体。
3.1.2 函数调用
在Python中,函数调用是执行已定义函数的过程。要调用一个函数,你需要使用函数名,后面跟着一对圆括号,并在括号内传递任何必要的参数。如果函数需要多个参数,它们应该用逗号分隔。
3.2 函数的参数与返回值
3.2.1 函数参数
函数参数是传递给函数的数据,它可以是任何类型的值,如整数、字符串、列表、字典等。函数可以定义任意数量的参数,这些参数在函数被调用时传递。参数可以是位置参数、关键字参数、默认参数、可变参数和关键字可变参数。
位置参数
位置参数是最简单的参数类型。在函数定义中,它们按照顺序排列,而在函数调用时,也必须按照相同的顺序提供这些参数
def greet(name, age):
print(f"Hello, {name}! You are {age} years old.")
# 调用函数时,参数需要按照定义的顺序传递
greet("Alice", 30) # 输出:Hello, Alice! You are 30 years old.
关键字参数
关键字参数允许在函数调用时明确指定参数的值,即使它们的顺序与函数定义中的顺序不同。
def greet(name, age):
print(f"Hello, {name}! You are {age} years old.")
# 使用关键字参数调用函数,可以明确指定每个参数的值
greet(age=30, name="Alice") # 输出:Hello, Alice! You are 30 years old.
默认参数
默认参数为函数提供了默认值,如果在调用函数时没有提供该参数的值,则使用默认值。
def greet(name, age=25):
print(f"Hello, {name}! You are {age} years old.")
# 调用函数时,可以省略age参数,它将使用默认值25
greet("Alice") # 输出:Hello, Alice! You are 25 years old.
可变参数
可变参数允许函数接收任意数量的位置参数。在函数定义中,这些参数以星号(*)开头。
def print_numbers(*numbers):
for number in numbers:
print(number)
# 调用函数时,可以传递任意数量的参数
print_numbers(1, 2, 3, 4, 5) # 输出:1 2 3 4 5
关键字可变参数
关键字可变参数允许函数接收任意数量的关键字参数。在函数定义中,这些参数以双星号(**)开头。
def greet_people(**people):
for name, age in people.items():
print(f"Hello, {name}! You are {age} years old.")
# 调用函数时,可以传递任意数量的关键字参数
greet_people(Alice=30, Bob=25, Charlie=35)
# 输出:
# Hello, Alice! You are 30 years old.
# Hello, Bob! You are 25 years old.
# Hello, Charlie! You are 35 years old.
3.2.2 函数返回值
函数的返回值是函数执行完成后返回给调用者的数据。在Python中,可以使用return
语句来指定函数的返回值。如果函数中没有return
语句,或者return
语句后面没有跟随任何值,则函数返回None
。
def add(a, b):
result = a + b
return result # 返回a和b的和
# 调用函数并捕获返回值
sum_value = add(3, 5)
# 打印返回值
print(sum_value) # 输出:8
3.2.3 特殊函数
匿名函数
在Python中,匿名函数(也称为lambda函数)是一种简洁的定义单行函数的方式。它们通常用于需要一个简短函数作为参数传递的场景,例如排序列表或作为回调函数使用。Lambda函数允许你定义函数而无需使用def
关键字来正式声明一个函数。
Lambda函数的基本语法如下:
lambda arguments: expression
其中:
arguments
是函数的参数,可以有多个,用逗号分隔。expression
是返回值的表达式。
Lambda函数只能有一个表达式,并且没有return
语句或def
关键字。它们实际上是函数对象,可以像普通函数一样使用。
下面是一些使用lambda函数的例子:
对一个列表进行排序:
# 使用lambda函数作为sort()方法的key参数
numbers = [4, 2, 9, 6, 20, 1, 3, 12]
numbers.sort(key=lambda x: x % 2 == 0) # 根据是否为偶数排序
print(numbers) # 输出: [1, 3, 9, 12, 4, 6, 20, 2]
过滤列表中的元素:
# 使用lambda函数作为filter()函数的第一个参数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # 输出: [2, 4, 6, 8]
递归函数
递归函数是一种特殊类型的函数,它在其定义中直接或间接地调用自身。递归函数通常用于解决可以分解为更小、相似子问题的问题。这些问题通常具有递归的性质,即问题的解决方案可以通过解决更小规模的相同问题来获得。
递归函数的基本结构通常包括两部分:
-
基本情况(Base Case):这是递归终止的条件,通常是一个或多个不需要进一步递归的情况。当递归到达这些条件时,它将停止并返回结果。
-
递归情况(Recursive Case):这是函数调用自身的部分。它将问题分解为更小规模的子问题,并递归地解决这些子问题。
下面是一个使用递归实现的简单例子:计算阶乘(factorial)。
def factorial(n):
# 基本情况
if n == 0 or n == 1:
return 1
# 递归情况
else:
return n * factorial(n - 1)
# 测试递归函数
print(factorial(5)) # 输出: 120
3.3 模块和包
3.3.1 模块的导入
在Python中,模块是一个包含Python代码的文件,该文件可以被其他Python程序或模块导入并使用。模块允许你组织和重用代码,这对于大型项目来说特别有用,因为它可以帮助你保持代码的整洁和模块化。
要导入一个模块,你需要使用import
语句。下面是一些导入模块的不同方式:
基本导入:
当你导入一个模块时,Python会查找该模块并将其加载到内存中。然后,你可以使用该模块中定义的函数、类和变量。
import math
print(math.sqrt(16)) # 输出: 4.0
导入并赋予别名:
如果模块名太长或与当前命名空间中的其他名称冲突,你可以给模块指定一个别名。
import math as m
print(m.sqrt(16)) # 输出: 4.0
从模块中导入特定的部分:
如果你只需要模块中的某些部分(例如函数或类),你可以直接从模块中导入它们。
from math import sqrt
print(sqrt(16)) # 输出: 4.0
导入模块中的所有内容:
使用*
可以导入模块中的所有内容,但这通常不推荐,因为它可能导致命名空间的污染。
from math import *
print(sqrt(16)) # 输出: 4.0
print(pi) # 输出: 3.141592653589793
动态导入:
你还可以使用importlib
模块来动态地导入模块。这在运行时根据某些条件决定导入哪个模块时非常有用。
import importlib
math_module = importlib.import_module('math')
print(math_module.sqrt(16)) # 输出: 4.0
相对导入:
在包(包含多个模块的目录)内部,你可能希望使用相对导入来引用其他模块。相对导入使用.
来表示当前包,而..
表示父包。
假设你有如下的包结构:
mypackage/
__init__.py
module_a.py
module_b.py
在module_b.py
中,你可以这样导入module_a
:
from . import module_a
或者,如果module_a
在module_b
的父包中:
from .. import module_a
小提示:
导入模块时,Python会按照特定的顺序查找模块:首先在当前目录查找,然后查找sys.path
中列出的目录,最后查找Python的安装目录。你可以通过修改sys.path
来添加自定义的模块搜索路径。
请注意,导入模块时可能会发生各种错误,例如ModuleNotFoundError
(如果模块不存在)或ImportError
(如果模块存在但无法正确导入)。因此,在导入模块时,最好使用try...except
语句来处理可能的错误。
3.3.2 包的导入
在Python中,包(package)是一种组织模块的方式,它允许你将相关的模块分组到一个目录下,并通过一个统一的命名空间来访问它们。包的导入稍微有些不同于单个模块的导入,但基本的import
语句仍然适用。
首先,确保你的包的结构是正确的。一个包应该包含一个特殊的文件__init__.py
,这个文件可以是空的,但它标志着该目录被视为一个包。此外,包内可以包含多个模块文件,每个文件都是一个Python模块。
例如,你有一个名为mypackage
的包,它包含两个模块module1.py
和module2.py
,那么你的目录结构应该如下:
mypackage/
__init__.py
module1.py
module2.py
要导入包中的模块,你可以使用以下几种方法:
导入整个包:
你可以导入整个包,然后使用点号.
来访问包内的模块。
import mypackage
mypackage.module1.some_function()
从包中导入特定模块:
from mypackage import module1
module1.some_function()
从包中导入多个模块:
与导入单个模块类似,你可以一次导入多个模块。
from mypackage import module1, module2
module1.some_function()
module2.another_function()
从包中导入模块的所有内容:
你也可以使用*
来导入模块中的所有内容,但这通常不推荐,因为它可能会导致命名空间的污染。
from mypackage.module1 import *
使用包的相对导入:
如果你正在包的一个模块内部,并希望导入同一包中的另一个模块,你可以使用相对导入。
在module2.py
中:
from . import module1
module1.some_function()
或者,如果module1
在父包中:
from .. import module1
module1.some_function()
请注意,包的导入可能受到Python解释器搜索路径的影响。如果包不在Python解释器的搜索路径中,你可能需要使用sys.path.append()
或sys.path.insert()
来添加包含包的目录。
另外,如果你想安装并使用第三方包,通常可以通过Python的包管理工具pip来安装。例如,要安装名为example_package
的第三方包,你可以在命令行中运行:
pip install example_package
第四章 面向对象
4.1 初识类与对象
在Python中,类(Class)是一种用户定义的数据类型,用于创建对象(Object)。对象是具有属性和方法的实例。属性是对象的数据成员,而方法是对象的行为或功能。
下面是一个简单的Python类定义的例子:
class MyClass:
# 这是一个类变量,所有实例共享同一个类变量
class_variable = "I am a class variable"
def __init__(self, name):
# 这是一个实例变量,每个实例都有自己独立的实例变量
self.instance_variable = name
def print_name(self):
# 这是一个实例方法,需要通过实例来调用
print(self.instance_variable)
@staticmethod
def print_class_variable():
# 这是一个静态方法,不需要通过实例来调用,可以直接通过类名调用
print(MyClass.class_variable)
# 创建一个MyClass的实例
my_instance = MyClass("Alice")
# 访问实例变量
print(my_instance.instance_variable) # 输出: Alice
# 调用实例方法
my_instance.print_name() # 输出: Alice
# 访问类变量
MyClass.print_class_variable() # 输出: I am a class variable
my_instance.print_class_variable() # 输出: I am a class variable
在这个例子中,MyClass
是一个类的名称,__init__
是一个特殊的方法,称为构造器(constructor),它会在创建类的实例时被自动调用。self
是一个指向实例本身的引用,在类的方法定义中总是作为第一个参数出现。
print_name
是一个实例方法,它可以通过类的实例来调用,并且可以通过 self
参数来访问实例的属性和其他方法。
print_class_variable
是一个静态方法,它使用 @staticmethod
装饰器来定义。静态方法不需要通过实例来调用,可以直接通过类名来调用,并且它们不能访问或修改实例的状态(即实例变量)。
class_variable
是一个类变量,它属于类本身而不是任何特定的实例。所有的实例共享同一个类变量。
instance_variable
是一个实例变量,每个实例都有自己独立的实例变量副本。
在Python中,类还支持继承、多态等其他面向对象的特性。继承允许你创建一个新类,该类继承自一个或多个已有的类(父类或基类),并可以添加或覆盖方法。多态则是指不同对象对同一消息产生不同的行为。
4.2 类对象的学习
4.2.1 类的定义
# 定义一个简单的Python类
class Person:
def __init__(self, name, age):
# 构造器,初始化对象的属性
self.name = name
self.age = age
def introduce(self):
# 定义一个方法,用于介绍自己
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
# 使用类创建对象
# 传递'Alice'和30作为参数给Person类的构造器
alice = Person('Alice', 30)
# 调用对象的方法
alice.introduce() # 输出: Hello, my name is Alice and I am 30 years old.
4.2.2 类的成员与成员方法
在Python类中,成员(Member)可以是属性(Attributes)或方法(Methods)。属性是类的变量,而方法是类的函数。
属性(Attributes)
属性是类的变量,它们可以是实例属性(Instance Attributes)或类属性(Class Attributes)。
实例属性
实例属性是分配给类实例的属性,每个实例都有它们自己的属性副本。实例属性通常在__init__
方法中使用self
参数来定义和初始化。
class MyClass:
def __init__(self, name):
self.name = name # 实例属性
# 创建两个实例
instance1 = MyClass("Alice")
instance2 = MyClass("Bob")
# 访问实例属性
print(instance1.name) # 输出: Alice
print(instance2.name) # 输出: Bob
# 修改实例属性
instance1.name = "Alice Smith"
print(instance1.name) # 输出: Alice Smith
print(instance2.name) # 输出: Bob,未受影响
类属性
类属性是分配给类的属性,而不是类的实例。类属性在所有实例之间是共享的。
class MyClass:
class_variable = "I am a class variable" # 类属性
# 创建两个实例
instance1 = MyClass()
instance2 = MyClass()
# 访问类属性
print(instance1.class_variable) # 输出: I am a class variable
print(instance2.class_variable) # 输出: I am a class variable
# 修改类属性
MyClass.class_variable = "Changed class variable"
print(instance1.class_variable) # 输出: Changed class variable
print(instance2.class_variable) # 输出: Changed class variable,所有实例都受到影响
方法(Methods)
方法是类的函数,它们通常通过实例来调用,并可以通过self
参数来访问实例属性和其他方法。
class MyClass:
def __init__(self, name):
self.name = name # 实例属性
def introduce(self): # 实例方法
print(f"Hello, my name is {self.name}.")
# 创建实例
instance = MyClass("Alice")
# 调用方法
instance.introduce() # 输出: Hello, my name is Alice.
除了实例方法外,Python类还支持类方法(Class Methods)和静态方法(Static Methods)。
类方法
类方法使用@classmethod
装饰器来定义,它们可以通过类名或实例来调用,并且第一个参数是类本身,通常命名为cls
。
class MyClass:
@classmethod
def class_method(cls):
print("This is a class method.")
# 通过类名调用类方法
MyClass.class_method() # 输出: This is a class method.
# 通过实例调用类方法
instance = MyClass()
instance.class_method() # 输出: This is a class method.
静态方法
静态方法使用@staticmethod
装饰器来定义,它们不接收特殊的第一个参数(如self
或cls
),并且可以通过类名或实例来调用。
class MyClass:
@staticmethod
def static_method():
print("This is a static method.")
# 通过类名调用静态方法
MyClass.static_method() # 输出: This is a static method.
# 通过实例调用静态方法
instance = MyClass()
instance.static_method() # 输出: This is a static method.
4.3 类的继承
1.)在Python中,类的继承是面向对象编程的一个重要特性,它允许我们创建一个新的类(子类或派生类)来继承另一个类(父类或基类)的属性和方法。这样,子类就可以重用父类的代码,同时还可以添加或覆盖父类的功能。
下面是一个简单的Python类继承的例子:
# 父类
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现此方法")
# 子类
class Dog(Animal):
def speak(self):
return "汪汪汪!"
# 另一个子类
class Cat(Animal):
def speak(self):
return "喵喵喵!"
# 创建Dog对象并调用speak方法
dog = Dog("旺财")
print(dog.speak()) # 输出: 汪汪汪!
# 创建Cat对象并调用speak方法
cat = Cat("小花")
print(cat.speak()) # 输出: 喵喵喵!
在这个例子中,Animal
类是一个父类,它定义了一个 speak
方法,但该方法没有实现(使用了 NotImplementedError
异常)。Dog
和 Cat
类分别继承了 Animal
类,并且各自实现了 speak
方法。
2.) Python还支持多重继承,即一个类可以继承多个父类。这可以通过在类定义时列出多个父类来实现,多个父类之间用逗号分隔。
# 多重继承
class Mammal(Animal):
def give_birth(self):
return "哺乳动物通常胎生。"
class Bat(Mammal, Animal): # Bat类继承了Mammal和Animal两个类
def fly(self):
return "蝙蝠会飞。"
bat = Bat("小蝙蝠")
print(bat.speak()) # 输出: 汪汪汪!或喵喵喵!,取决于Bat类如何实现speak方法
print(bat.give_birth()) # 输出: 哺乳动物通常胎生。
print(bat.fly()) # 输出: 蝙蝠会飞。
在多重继承中,如果子类调用了与父类同名的方法,那么Python会按照方法解析顺序(Method Resolution Order, MRO)来确定最终调用哪个父类的方法。MRO是Python解释器用来确定继承关系中方法调用的一个规则。
请注意,虽然继承提供了代码重用和扩展性的好处,但过度使用或不当地使用继承也可能导致代码难以理解和维护。因此,在设计类结构时,需要权衡继承的利弊,并根据实际情况选择最合适的类继承策略。
4.4 类的重写
在Python中,重写(Overriding)是指子类可以定义与父类中同名的方法,从而在调用该方法时执行子类中的实现,而不是父类中的实现。这样,子类可以根据需要定制或扩展父类的行为。
当子类需要改变或扩展父类的方法行为时,就可以通过重写来实现。在Python中,重写方法非常直接,只需要在子类中定义与父类同名的方法即可。
下面是一个简单的例子,展示了如何在Python中重写类的方法:
# 父类
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
def start_engine(self):
print(f"The engine of {self.make} {self.model} starts.")
def stop_engine(self):
print(f"The engine of {self.make} {self.model} stops.")
# 子类
class Car(Vehicle):
def start_engine(self):
# 重写父类的start_engine方法
print("The car engine cranks.")
super().start_engine() # 调用父类的start_engine方法
def stop_engine(self):
# 重写父类的stop_engine方法
print("The car engine turns off.")
super().stop_engine() # 调用父类的stop_engine方法
# 创建Car对象并调用方法
my_car = Car("Toyota", "Camry")
my_car.start_engine() # 输出: The car engine cranks. The engine of Toyota Camry starts.
my_car.stop_engine() # 输出: The car engine turns off. The engine of Toyota Camry stops.
在这个例子中,Car
类继承了 Vehicle
类,并重写了 start_engine
和 stop_engine
方法。当调用 my_car.start_engine()
时,Python会首先查找 Car
类中是否存在 start_engine
方法,如果存在则执行该方法;如果不存在,则会沿着继承链向上查找,直到找到该方法或到达继承链的顶端。
在重写方法时,可以使用 super()
函数来调用父类中的同名方法。super()
函数返回一个临时的父类对象,可以用它来调用父类的方法。在上面的例子中,super().start_engine()
和 super().stop_engine()
分别调用了 Vehicle
类中的 start_engine
和 stop_engine
方法。
重写是一种强大的机制,它允许子类根据特定需求定制父类的行为,同时保持与父类的兼容性。然而,过度使用重写或在不适当的情况下重写方法可能会导致代码难以理解和维护,因此应该谨慎使用。
4.5 异常处理
在Python中,异常处理是一种编程技术,用于处理程序运行时可能出现的错误或异常情况。通过使用异常处理,您可以优雅地处理错误,提供有用的错误消息,并允许程序在出现问题时继续运行或安全地终止。
Python提供了几个内置的关键字来处理异常,主要是try
, except
, finally
, 和 raise
。
-
try: 您将可能引发异常的代码块放在
try
块中。 -
except: 如果
try
块中的代码引发了异常,则执行与该异常类型匹配的except
块中的代码。可以有多个except
子句来处理不同类型的异常,还可以有一个不带条件的except
子句作为最后的后备。 -
finally: 无论是否发生异常,
finally
块中的代码总是会被执行。这通常用于清理资源,如关闭文件或网络连接。 -
raise: 用于手动触发异常。
下面是一个简单的异常处理示例:
try:
# 尝试执行一些代码
result = 10 / 0
except ZeroDivisionError:
# 如果发生ZeroDivisionError异常,执行此代码块
print("除数不能为零!")
except Exception as e:
# 捕获其他类型的异常
print(f"发生了一个错误: {e}")
else:
# 如果没有异常发生,执行此代码块
print("计算成功!")
finally:
# 无论是否发生异常,都执行此代码块
print("程序结束.")
在上面的例子中,try
块中的代码会引发ZeroDivisionError
,因此会执行与该异常匹配的except
块。如果没有异常发生,else
块会被执行。无论哪种情况,finally
块都会执行。
注意,使用except Exception as e
可以捕获几乎所有类型的异常,并将异常信息存储在变量e
中。然而,通常建议只捕获您知道如何处理的异常类型,以避免掩盖其他可能的问题。
此外,您还可以使用raise
关键字在代码中手动抛出异常:
if some_condition:
raise ValueError("Invalid value provided")
我们也可以自定义异常类,,比如学生成绩不能为负数的情况。下面是一个如何创建这样的自定义异常类的示例:
# 自定义一个名为NegativeScoreError的异常类
class NegativeScoreError(ValueError):
def __init__(self, message):
super().__init__(message)
# 定义一个函数来设置学生成绩,使用自定义异常类
def set_student_score(student_name, score):
if score < 0:
# 如果成绩是负数,则抛出自定义异常
raise NegativeScoreError(f"学生 {student_name} 的成绩不能是负数: {score}")
else:
# 如果成绩有效,则打印确认信息
print(f"学生 {student_name} 的成绩已设置为: {score}")
# 使用函数并处理自定义异常
try:
set_student_score("Alice", -10) # 尝试设置一个负数的成绩
except NegativeScoreError as e:
# 捕获自定义异常并打印错误消息
print(e)
# 尝试设置一个有效的成绩
try:
set_student_score("Bob", 85)
except NegativeScoreError:
# 这个异常块不会执行,因为成绩是正数
print("捕获到负成绩异常,但这里不会执行")
在这个例子中,我们创建了一个名为NegativeScoreError
的自定义异常类,它继承自ValueError
。然后,我们定义了一个set_student_score
函数,该函数接受学生姓名和成绩作为参数。如果成绩是负数,函数会抛出NegativeScoreError
异常。
在try
块中,我们尝试调用set_student_score
函数来设置学生成绩。如果抛出NegativeScoreError
异常,except
块会捕获它并打印出错误消息。如果成绩是有效的(即非负数),则不会抛出异常,并且会打印出确认信息。
这样,通过使用自定义异常类,我们可以更清晰地传达程序中发生的特定错误条件,并且可以根据这些错误条件采取适当的错误处理措施。
附录资料
列表推导式https://blog.csdn.net/weixin_58141420/article/details/136498170