Python语法基础(3月30日)
本次课程对之前训练进行总结,对未训练的部分进行整体讲解,内容比较多,进展快,需要多次重复训练。
1.1 变量、缩进和注释
变量相当于一个代号,是一个存放数据值的容器,通过变量名我们可以找到对应的数据,在Python中,变量的命名必须以字母或下划线开头,后面可以跟任意数量的字母、数字、下划线的组合,同时,使用=可以对变量赋值,写成如下形式
1
2
缩进是Python中非常重要的一部分,不同于其他语言,Python不使用{}或者()等来分隔代码块,而是使用缩进来分隔代码块,且一定要记住缩进是使用键盘上的Tab键,比如for语句
1
2
3
4
5
Hello
在上面的代码中,i = i + 1和print(i)语句之前都有缩进,缩进就代表了代码块的开始,而缩进结束就代表代码块的结束。
在Python中以#开始或者被'''包裹的部分都是代码的注释,修改注释中的内容不影响代码的运行结果
1
2
3
1.2 数据类型
1.2.1 数字
数字类型包含许多不同的类型,比如整数,浮点数等,主要用于计算等场景,可以通过一些函数将字符串转为对应的数字类型
在Python中共有三种数字类型: - int:有符号整形 - float:浮点型 - complex:复数
<class 'int'>
<class 'float'>
<class 'str'>
<class 'int'>
<class 'str'>
<class 'float'>
同时数字类型可以进行运算等操作
3
<class 'int'>
6.1415926
<class 'float'>
1.2.2 字符串
字符串是以 单引号 或 双引号 或 三引号 括起来的任意文本 这里所有的引号都是英文的引号
a = 'this is a'
b = "this is b"
c = '''this is c'''
print(a)
print(b)
print(c)
print(type(a))
print(type(b))
print(type(c))
this is a
this is b
this is c
<class 'str'>
<class 'str'>
<class 'str'>
在声明字符串时,单引号和双引号是等价的,而三引号更多的用于书写注释
a 等于 b 为 True
字符串有许多常用的方法,比如转换大小写,替换指定字符等
upper
LOWER
this is b
字符串可以进行格式化,使用format方法使用指定值来填充占位符
this is apple
1.3 数据结构
1.3.1 列表
列表是一种有序的数组,可以随时添加和删除其中的元素,且在列表中,每个元素都有一个数字来唯一确定它的位置,称为索引,且索引是从0开始的。
1对应的索引为0,2对应的索引为1,同理,3对应的索引为2.
a = [1,2,3] # 声明列表
print(a)
print(len(a)) # 输出列表长度
a.append(4) # 在列表末尾增加元素4
print(a)
print(len(a))
a.pop() # 删除末尾的元素
print(a)
print(len(a))
a.remove(1) # 删除指定的元素
print(a)
print(len(a))
a.insert(1,10) # 在列表索引为1的位置插入元素10
print(a)
print(len(a))
a[0] = 100 # 用100覆盖列表索引位置为0的元素
print(a)
print(len(a))
[1, 2, 3]
3
[1, 2, 3, 4]
4
[1, 2, 3]
3
[2, 3]
2
[2, 10, 3]
3
[100, 10, 3]
3
列表根据索引来取值,索引从0开始,如果下标超出列表的长度就会报错,出现IndexError异常
1
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[8], line 3
1 b = [1, 2, 3]
2 print(b[0])
----> 3 print(b[3])
IndexError: list index out of range
索引也可以取负值,负数索引的含义是从列表的末尾往前计数。例如索引-1的含义是列表的最后一个元素
3
1
列表除了使用索引的方法来取值,也可以使用字符串部分提到的切片方法
切片操作的语法与字符串部分是相同的,上面的切片同样返回list中从start开始(包括start位置的元素)到end结束(不包括end位置)的元素[3, 4]
有时候需要切片的内容并不是连续的,例如在一定范围内,每隔两个元素取一个元素的情况。此时可以指定切片的步长来实现这种功能
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[2:9]) # a的第3到第9个元素
print(a[2:9:2]) # a的第3到第9个元素,但每两个元素仅保留第一个
print(a[2:9:3]) # a的第3到第9个元素,但每三个元素仅保留第一个
[3, 4, 5, 6, 7, 8, 9]
[3, 5, 7, 9]
[3, 6, 9]
1.3.2 元组
列表在创建后可以动态增加和删除值,而元组在生成之后无法修改,只能读取其中的值
(1, 2, 3)
<class 'tuple'>
1
(1, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [19], line 1
----> 1 a[0] = 1
TypeError: 'tuple' object does not support item assignment
另外需要注意的是,在声明元组时如果只有一个元素,需要在元素的后面加一个,号,写成如下形式
b = (1) # 声明只有一个元素的元组,但是未加逗号
print(b)
print(type(b)) # 为int类型,而不是tuple
c = (1,) # 当只有一个元素声明元组时,加上逗号
print(c)
print(type(c)) # 此时类型为tuple
1
<class 'int'>
(1,)
<class 'tuple'>
1.3.3 集合
列表和元组都允许重复的元素存在,而集合中的所有元素都是唯一的,不存在重复值,可以通过set(list)将列表或者元组转为set,去除其中重复的元素
[1, 2, 2]
(1, 2, 2)
{1, 2}
{1, 2}
同时集合可以动态的添加和删除值,但无法通过下标来取值
s = {1, 2, 2, 3}
print(s)
print(len(s))
s.add(5)
s.add(1) # 添加集合中已有的值会直接过滤掉
print(s)
print(len(s))
s.remove(5) # 删除指定元素
print(s)
print(len(s))
print(s[0])
{1, 2, 3}
3
{1, 2, 3, 5}
4
{1, 2, 3}
3
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [22], line 14
11 print(s)
12 print(len(s))
---> 14 print(s[0])
TypeError: 'set' object is not subscriptable
多个集合可以方便的取交集和并集以及差集
{3}
{1, 2, 3, 4, 5}
{1, 2}
1.3.4 字典
字典是存储键(key)-值(value)对的数据结构,能够快速的找到键对应的值,一般用来存储一些对应关系
d1 = {"a":1, "b":2} # 创建一个映射关系,其中a对应1,b对应2
print(d1["a"]) # 取key为a对应的value
print(d1["b"]) # 取key为b对应的value
d1["a"] = 100 # 更改key为a的value为100
print(d1)
print(d1.keys()) # 输出字典所有的key
print(d1.values()) # 输出字典所有的value
for k,v in d1.items(): # 遍历整个字典,输出所有的key-value对
print(k,v)
1
2
{'a': 100, 'b': 2}
dict_keys(['a', 'b'])
dict_values([100, 2])
a 100
b 2
通过对字典中不存在的键赋值,可以添加键值对到字典中。使用关键字 del 可以从字典中删除对应键值对
{}
{'a': 1}
{}
Python中提供了一些处理字典的函数
d1 = dict.fromkeys(["a", "b", "c"]) # 创建指定了键,但值为 None 的字典
print(d1)
d1 = {"a":1, "B":9, "C":8, "D":7, "e":5, "f":6}
d2 = {"A":1, "B":2, "C":3, "D":4}
d2.pop("A") # 将键对应的键值对从字典中删除
print(d2)
d2.update(d1) # 使用另一个字典的键值对来更新字典,字典中不存在的键值对直接添加、存在的键值对更新其值
print(d2)
d2.clear() # 删除字典中所有的键值对
print(d2)
{'a': None, 'b': None, 'c': None}
{'B': 2, 'C': 3, 'D': 4}
{'B': 9, 'C': 8, 'D': 7, 'a': 1, 'e': 5, 'f': 6}
{}
1.4 运算符
这里主要介绍Python中算术运算符、赋值运算符、比较运算符、逻辑运算符和成员运算符
1.4.1 算术运算符
算术运算符也就是我们常说的加减乘除、幂运算以及整除和取余运算,在Python中分别为+、-、*、/、**、//和%。
3
hello Python
[0, 1, 3, 4]
-1
a = 1
b = 2
print(a * b) # 计算a乘b的值
c = 'hello'
print(c * 5)# 可以用来重复对应的字符串
l1 = [0,1]
print(l1 * 3) # 可以用来重复列表,在初始化指定长度的列表时很有用
2
hellohellohellohellohello
[0, 1, 0, 1, 0, 1]
0.5
8
2
1
1.4.2 赋值运算符
赋值运算符的作用就是对变量做相应的运算,然后将其赋值给变量,在Python中,赋值运算符有以下几个: - +=: 对变量做加法运算,然后赋值给变量 - -=:对变量做减法运算,然后赋值给变量 - *=:对变量做乘法运算,然后赋值给变量 - /=:对变量做除法运算,然后赋值给变量 - **=:对变量做幂运算,然后赋值给变量
11
6
30
6.0
36.0
1.4.3 比较运算符
比较运算符对应于数学中常用的大于、小于、大于等于、小于等于以及等于,在Python中对应的运算符分别为>、<、>=、<=、==和!=,特别需要注意的是,在Python中,一个等号=代表给变量赋值,而两个等号==才代表比较两个变量的值是否相等。感叹号加上等号!=表示不等于,表达与相等相反的逻辑
a = 1
b = 2
c = 3
print(a > b) # 判断a是否大于b
print(b <= 10) # 判断b是否小于等于10
print(a == 1) # 判断a的值是否为1
print(c != 3) # 判断c的值是否不等于3
False
True
True
False
1.4.4 逻辑运算符
逻辑运算符也就是与、或者和非,在Python中对应的运算符分别为and、or和not,逻辑运算符多用在Python中的条件语句中
a = 1
b = 5
if a > 1 and b > 2:
print("满足条件与")
if a > 1 or b > 2:
print("满足条件或")
if not a > 1:
print("满足条件非")
满足条件或
满足条件非
1.4.5 成员运算符
成员运算符表达的含义是对应的变量是否存在于另一个变量当中,在Python中的运算符分别为in和not in
True
False
False
1.5 Python语句
1.5.1 条件语句
if语句 \ if语句根据条件的满足与否来控制代码的执行,如果条件满足就会执行对应部分的代码
按照上面的代码,如果condition满足(也即condition为True),就会执行code_1,否则就会执行code_2target = 100
guess = int(input("input guess"))
if target == guess :
print("equal")
else:
print("not equal")
input guess 100
equal
# 根据不同的字符串输出不同的结果
s = "apple"
if s == "apple":
print("this is apple")
elif s == "banana":
print("this is banana")
else:
print("other")
this is apple
1.5.2 循环语句
循环语句可以进行迭代和重复操作,比如计算从1到10的和,可以使用循环语句来进行操作
for语句
for语句可以取出集合或者列表中的对象进行一些重复的操作
value is 1
value is 2
value is 3
value is 4
value is 5
range(a,b),用来产生从a到b范围内的数,同样是采取前闭后开的原则
0
1
2
3
4
可以注意到for循环只能够依次取出可迭代对象中的每个对象,而并不是通过下标来进行操作,那么在某些场景下我们需要下标时,可以通Python提供的enumerate方法
0 100
1 200
2 300
另外一个场景是我们想要同时循环多个列表,来做一些操作,这时可以通Python提供的zip函数,示例如下:
100 1
200 2
300 3
while语句
while语句可以按照条件来判断是否执行对应的语句,
5
4
3
2
1
如果循环条件设置不当,while 语句可能陷入无法停止的循环,称为死循环。死循环影响程序的正常进行,所以应该想办法避免。
下面的例子演示了一个错误的,无法停止的死循环。当出现死循环时,以jupyter notebook 为例,可以通过点击运行按钮右边的方块图标的中断按钮,来停止程序的执行,避免系统崩溃
a = 1 while (a == 1): print("循环进行中")
循环控制语句
在Python当中,循环控制语句以下几个: - break:终止当前循环,跳出整个循环 - continue:终止当次循环,直接执行下一次循环 - pass:不执行任何操作,常用于占位
0
0
2
4
1.5.3 条件语句和循环语句结合
将条件语句和循环语句组合起来可以实现更多功能
# 计算1到10中偶数的累积和
sum_value = 0
for i in range(1,11):
if (i % 2) != 0: # 判断是否为奇数
continue # 如果是奇数则跳过一次循环
sum_value += i
print(sum_value)
30
1.5.4 异常处理语句
经过上面的学习,我们已经能够初步的了Python的相关语法,但是即使我们熟悉了相关语法,在代码执行时仍然可能会出现错误,这种执行时检测到的错误称为异常(Exception),当我们的程序遇到异常时,程序就会退出,同时,报出的异常中会包含错误的信息,而且异常有多种类型,分别表示不同的错误
比如我们已经见过的数据越界异常等,如下:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In [55], line 2
1 a = list([1,2])
----> 2 print(a[2])
3 print("end")
IndexError: list index out of range
正常情况下, 遇到异常时,程序会退出同时会报告出我们所遇到的错误,但有些时候,我们不希望程序退出,这时,就需要我们对异常进行处理。
temp_list = [1,2] # 声明一个只有两个元素的数组
try: # 异常处理关键字
print(">>>>>>>>>try<<<<<<<<<")
print(temp_list[2]) # 尝试打印超出数组长度的元素,会报IndexError异常
except IndexError as e: # 捕捉IndexError异常,并进行处理
print(">>>>>>>>>处理异常<<<<<<<<<")
print("catch IndexError,processing...")
print(e)
print("数组的长度为%s, 数组中的数据为%s" % (len(temp_list),temp_list))
>>>>>>>>>try<<<<<<<<<
>>>>>>>>>处理异常<<<<<<<<<
catch IndexError,processing...
list index out of range
数组的长度为2, 数组中的数据为[1, 2]
另外,无论代码是否出现了异常我们都想要执行一部分代码,这时可以使用finally关键字
temp_list = [1,2] # 声明一个只有两个元素的数组
print("example1")
try: # 异常处理关键字
print(">>>>>>>>>try<<<<<<<<<")
print(temp_list[2]) # 尝试打印超出数组长度的元素,会报IndexError异常
except IndexError as e: # 捕捉IndexError异常,并进行处理
print(">>>>>>>>>处理异常<<<<<<<<<")
print("catch IndexError,processing...")
print("数组的长度为%s, 数组中的数据为%s" % (len(temp_list),temp_list))
finally:
print(">>>>>>>>>finally<<<<<<<<<") # try后的代码出现了异常,进行了异常处理,然后执行了finally字段
print("\n\nexample2")
try: # 异常处理关键字
print(">>>>>>>>>try<<<<<<<<<")
print(temp_list[0]) # 不会出现异常的代码
except IndexError as e: # 捕捉IndexError异常,并进行处理
print(">>>>>>>>>处理异常<<<<<<<<<")
print("catch IndexError,processing...")
print("数组的长度为%s, 数组中的数据为%s" % (len(temp_list),temp_list))
finally:
print(">>>>>>>>>finally<<<<<<<<<") # try后的代码没有异常,直接执行了finally字段
example1
>>>>>>>>>try<<<<<<<<<
>>>>>>>>>处理异常<<<<<<<<<
catch IndexError,processing...
数组的长度为2, 数组中的数据为[1, 2]
>>>>>>>>>finally<<<<<<<<<
example2
>>>>>>>>>try<<<<<<<<<
1
>>>>>>>>>finally<<<<<<<<<
1.6 函数与库
在Python中,函数和库是用来减少代码复杂性和重复性的手段,对于Python中的函数就是将一些具有独立功能或者会被频繁使用的代码块进行组织并且命名的过程,来方便后续使用,进一步的,Python中的库就是将一些包含特定功能且被频繁使用的函数和其他内容进行封装的结果。在Python中用户可以自定义函数和库,同时系统也提供了大量的内置函数和标准库,常见的内置函数如len()、print(),这些内置函数不需要导入任何库就可以使用,而标准库则是在安装好Python或者Anaconda后,不需要安装第三方库就可以使用的一些库,比如datatime和os等
1.6.1 函数
在Python中,定义函数的方法有两种,一种是通过def关键字来定义函数,另一种是通过lambda关键字来定义简短的匿名函数
使用def关键字定义函数的结构如下:
def add(a,b): # 定义一个add函数
"""
add计算a+b的值并返回c
"""
return a + b
a = 1
b = 2
res = add(a,b) # 调用add函数,并且将其返回值赋给res
print(res)
3
def 关键字之后的代码块,也就是函数定义的内容中,使用的变量与代码块外部的变量是不同的。假设在函数定义的代码块中,和代码块外部的内容中,定义了同名的变量,这两个变量也不会互相影响。这是因为函数定义部分,和外部的代码,属于不同的作用域,每一个变量只能在自己的作用域之内起作用,无法影响作用域之外的内容
# 这里在外部作用域中创建了变量 a,其内容与函数定义的作用域的变量不相影响
a = "我在外部作用域"
print(a)
def add(n1, n2):
"""
这里在函数定义的作用域中创建了变量 a,其内容与外部作用域的变量不相影响
"""
a = "我在内部作用域"
print(a)
return n1 + n2
b = 2
c = 3
add(b, c)
print(a)
我在外部作用域
我在内部作用域
我在外部作用域
还可以用lambda关键字来定义函数。lambda关键字常用于定义匿名函数,这是一种没有名字且只允许包含一个表达式的函数,使用lambda关键字定义函数的语法如下
lambda关键字定义匿名函数的代码如下,以加法函数为例
3
sorted函数使用Python中用来对列表、或者其他自定义类型进行排序的方法,通过sorted函数可以将无序的列表变为有序。
[1, 2, 3, 5]
[5, 3, 2, 1]
通过结合sorted和lambda定义的匿名函数可以实现自定义排序的效果。代码如下所示。
tuple_list = [(2, 4),(1, 5), (3, 2)]
print(sorted(tuple_list))
print(sorted(tuple_list,key=lambda x:x[1]))
[(1, 5), (2, 4), (3, 2)]
[(3, 2), (2, 4), (1, 5)]
1.6.2 库
Python中的库生态非常丰富,除了Python中自带的标准库外,还有大量的第三方库,可以实现各种功能,比如非常常用的标准库datetime,可以用来格式化时间和计算时间之间的差值,另外,在后续的文本处理和数据分析内容中,也大量使用了一些第三方库,比如常用于中文分词的jieba,或者常用于处理数据处理的pandas库等。
而在Python中导入一个库是非常简单的,可以使用import关键字
12
同样也可以使用from ... import ...的语句来导入库中的特定功能模块
datetime.datetime(2023, 11, 23, 21, 21, 26, 722311)
有时候导入的库,或者库中的功能模块的名称难以记忆,可以使用import xxx as xxx和from xxx import xxx as xxx的语句临时将其修改为更容易记忆和使用的名称
datetime.datetime(2023, 11, 23, 21, 21, 27, 250804)
datetime.datetime(2023, 11, 23, 21, 21, 27, 634612)
有时候导入的库功能范围比较广、体积比较大,因此内部会进一步细分为多个子库。库中的子库通过xxx.xxx的形式来描述,使用import xxx.xxx 可以导入子库,同样也可以使用from xxx.xxx import xxx导入子库中的特定功能模块,和使用import xxx.xxx as xxx来在导入子库时临时修改名称方便记忆和使用
import os.path
filepath = "./data/example.txt"
print(os.path.basename(filepath))
print(os.path.dirname(filepath))
example.txt
./data
from os.path import basename
from os.path import dirname
filepath = "./data/example.txt"
print(basename(filepath))
print(dirname(filepath))
example.txt
./data
import os.path as mypath
filepath = "./data/example.txt"
print(mypath.basename(filepath))
print(mypath.dirname(filepath))
example.txt
./data
在导入库时需要注意库是否已经安装,如果导入没有安装的库,Python则会出现异常,这时可以通过pip或者conda来安装缺少的库
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In [70], line 1
----> 1 import not_exists
ModuleNotFoundError: No module named 'not_exists'
1.7 类
在我们想要描述一个对象的时候,往往会从对象所拥有的属性和方法来描述这个对象,这就Python中的类。通过定义类,一方面可以实现部分代码的复用,同一个类的实例可以使用同一份代码;另一方面可以方便对象的组织管理,将属于同一类的对象很好地组织起来
类可以作为类型的同义词。现实世界中每一个事物都属于一个类型中的个体,同时每一个事物除了具有类型的共性也有自己的个性,对应于Python中每一个对象都是一个类的实例。例如一只鸭子属于鸟类的一个个体,也就是“鸭子”对象是“鸟”类的一个实例。这就是类和实例之间的关系,在Python中使用类时,往往是先创建一个类的实例,然后调用该实例的函数
以下展示了一个简单类的定义,主要使Python中的class关键字,并创建了该类的一个实例,通过这个实例运行了类中定义的函数
class People: # 声明类的名字
# 构造方法,用来将类实例化
def __init__(self,name):
self.name = name # 初始化一个name属性
# 定义一个方法,用来输出hello 信息
def say_name(self):
hello_str = "hello my name is {}!".format(self.name)
print(hello_str)
def say(self):
print("people")
obj = People(name="Bob") # 创建一个类的实例,并传入name
obj.say_name()
obj.say()
hello my name is Bob!
people
可以看到,上面类的定义内容中,定义了一个名为 "__init__" 的函数,这就是类的构造函数。构造函数在创建类的实例时会被调用,例如上面执行 obj=People(name="Bob") 时,实际上调用了构造函数,执行构造函数的内容将字符串 "Bob" 赋值给了类的属性 name。也可以为类的构造函数设置默认值,这样当不特意指定构造函数的参数值时,构造函数会用默认的参数值来创建实例。下面的例子设置了构造函数的默认值,创建实例时不指定参数,而是使用默认的参数
class People: # 声明类的名字
# 构造方法,用来将类实例化
def __init__(self,name="Peter"):
self.name = name # 初始化一个name属性
# 定义一个方法,用来输出hello 信息
def say_name(self):
hello_str = "hello my name is {}!".format(self.name)
print(hello_str)
def say(self):
print("people")
obj = People() # 创建一个类的实例,并传入name
obj.say_name()
obj.say()
hello my name is Peter!
people
通过类的继承特性,可以实现代码的复用,比如以下的例子,子类可以继承父类所有的方法和属性,实现代码的复用,同时,子类也可以对父类的方法进行重写,实现多态。
class Student(People): # 继承People类
def __init__(self,name): # 同样需要构造函数
super(Student,self).__init__(name) # 调用父类的构造函数来初始化类
def say_more(self): # 声明方法
self.say_name() # 调用继承得到的方法
print("i'm student")
def say(self): # 重写父类的方法,实现多态
print("student")
student_obj = Student("Bob")
student_obj.say_more() # 调用方法
student_obj.say() # 调用重写后的方法
hello my name is Bob!
i'm student
student