Python笔记 #1 基础语法

本文最后更新于:2023年7月3日 中午

跟着贵系的暑培过了一遍语法,然而写代码时还是感到乏力,总觉得要打一遍才能记住,于是有了这篇博客。

本文部分内容参考了清华 AYF 同学的教程,部分参考了 Python 官方的一份 Tutorial,函数用法参考了 xyfJASON 的博客。本文将持续更新。

Python 特性

相比于 C 的编译型、弱类型、静态类型特点,Python 则是一种解释型、强类型、动态类型的语言。

交互式 vs 脚本

作为一种解释型语言,Python 不需要像 C 一样编译运行,它可以逐行运行代码,因此又分为交互式窗口运行与脚本运行两种模式:

  • 交互式窗口:在 CLI 输入 python,即可进入交互式窗口,输入一行代码即可运行。本文使用的交互式环境是 IPython,输入 ipython 即可呼出。
  • 脚本:在 CLI 输入 python xxx.py,就会依次执行整个脚本文件。本文使用的 IDE 是 PyCharm

Hello World

1
2
>>> print('Hello, world!') # 打印输出
Hello, world!

在交互式窗口,>>> 作为提示符,在 IPython 中则是 In [1]:。执行 exit() 或者按下 Ctrl+D 就能退出窗口。

注意到,这行代码中没有 ; 分号,可以直接运行而无需编译,字符串用了单引号,注释用 # 开始【与 C 不同】。

简单数据类型

变量类型

【与 C 不同】,Python 不用声明变量类型,解释器自动解释。

  • int:变长整数,默认是 4 字节,有需要时自动增长,用于高精度运算,还支持十六进制、八进制和二进制表示。
  • complex:自带的复数类型,表示为 real + imag*1j 的形式,虚部为 1 的时候不可省略 1,可以用 j 也可以用 J。实虚部分别为一个 float
  • float:8 字节浮点数,【相当于 C 的 double】。
  • bool:True 和 False,注意首字母大写,用作数值计算时与 C 一样视作 0 和 1。
  • NoneType: None,空值,常用于返回值、特判。

需要单独说明的是,Python 会存储所有的 -5 到 256 的整数,其他任何变量是这些值时,会被指向这个预先开好的内存,因此任何两个值为 5 的 int 变量都指向同⼀内存地址。

尽量用小写变量名(下划线法),这是 Python3 的主流命名方式。

运算符

这里列出常见的运算符,运算符可以重载,重载需要修改其对应的定义函数。

算术运算符

  • + - *【与 C 相同】
  • %35 % 4 == 3-35 % 4 == 135 % -4 == -1-35 % -4 == -3,【与 C 不同:负数对正数取模时返回正余数,而非像 C 那样返回负余数】
  • /__trudiv__,真除,得到 float 结果
  • //__floordiv__,除后向下取整(不是舍弃小数),得到 int 结果
  • **__pow__,幂运算

比较运算符

  • < <= > >= == != 【与 C 相同】

位运算符:

  • & | ^ ~ << >> 【与 C 相同】

赋值运算符

  • =:赋值号,不能被重载
  • += -= *= /= %= 【与 C 相同】
  • 注意 Python 中没有 ++ -- 的运算符,只能通过 += 1 实现

逻辑运算符

  • and or not 【类似 C 中的 && || ,具有短路机制
  • 对于 andor,通常用于条件分支 bool 的判断,如果非要连接 int 变量,得到的结果不会直接转换为 bool,而是返回能够得出结果最后一个变量【与 C 中的短路类似】

三目运算符

  • a if cond else b:相当于 C 中的 cond ? a : b,注意其参数顺序【与 C 不同】,但更贴近自然语言

特殊条件运算符

  • in:被包含于,详见下文「容器」,返回 bool
  • not inin 的否定,返回 bool
  • is:判断两个变量的地址是否相同,不可重载,返回 bool
  • is not:判断两个变量地址是否不同,不可重载,返回 bool

字符串

Python 将字符串封装成了基本类型并处理了多种运算,带来许多便利,注意基本类型本身是不可修改的,所谓修改其实是将重新生成另一个字符串,再将其赋值给目标。

此外,Python 中没有单独的字符类型,单个字符将被视为长度为 1 的字符串。【与 C 不同】,可以用 "" 或者 '' 括起字符串。

下面是一些常用函数,设 str 是一个字符串:

  • str.title():返回单词首字母大写,其余字母小写(不管以前是不是大写)的字符串
  • str.upper()str.lower():返回全大/小写的字符串
  • str1 + str2:返回用加号拼接的字符串【与 C++ 的 string 类似】
  • str * 3:返回重复三遍拼接的字符串
  • 制表符 \t,换行符 \n【与 C 相同】
  • str.lstrip()str.rstrip()str.strip(): 返回删除开头/末尾/两端空白的字符串
  • str.replace(str1, str2):将字符串中的单词 str1 全部替换成 str2
  • str.split(str1):以 str1 为分隔符把字符串拆成子串,并返回包含子串的列表,默认分隔符为空格
  • str.zfill(n):将数字字符串补全前导零n 为总位数
  • ' '.join("a", "b", "c"):用 ' ' 作为连接符,拼接所有子串得到一个长字符串

此外还有一种跨行字符串,用 ’‘’”“” 括起来,由于脚本中顺序执行时不会输出变量值,这类字符串常用于跨行注释,特别是函数头注释。

输入输出与编码

此处说明几个重要函数:

  • len(obj):获取 obj 的长度,常用于获取字符串(注意是 Unicode,因此中文和英文字符都占 1 位)、字节串、容器的长度
  • str(a): 把数字(整型或浮点型) a 转换成字符串
  • chr(0x4f60):将整型变量 i 转化成单个字符
  • ord('你'):获取单个字符的编码(Unicode),注意在 Unicode 中,英文字母的编码有意设置与 ASCII 码一致

最常用的输出语句 print,本质上是将变量转化为字符串输出,在末尾自动换行。该函数可以有多个变量,变量间用 , 分隔,输出时会用空格隔开。

如果要在一句话中插入许多变量,这条 print 语句可能会很丑陋,因此 Python 中有三种格式化字符串的方法。

  • %:如 print('I am %d' % (age)),【与 C 类似】
  • str.format():如 print('hello, {}'.format(name))
  • f-string:如 print(f'hello,{name}.I am {age}')

其中 f-string 是 Python3.6 的新特性,最为直观便利。

此外,input('Press ENTER to continue') 是常见的一种输入语句,会显示对应的提示内容,读入内容以以字符串存储,可以用 int(input())map(int, input().split()) 处理。

字节串

bytes 即是 Python 中的字节串,它表示最纯粹的二进制数据,【类似 C 的 unsigned char *】,但是在显示上它仅支持 ASCII 显示,因此用肉眼看显得有些不伦不类,通常它只存在于数据的处理过程中。

bytes 的构造与字符串类似,但是要加一个 b 做前导,如 print(b'\x41')

容器

Python 提供了一系列内置容器,它们如同 C++ 的 STL ⼀样,不过比 STL 的用法灵活得多。

同样先介绍几个重要函数:

  • type(obj):可以获取参数 obj 的类型
  • isinstance(obj, class_or_tuple):可以判断 obj 是不是类的实例
  • id(obj):获取 obj 的地址, a is b 等价于 id(a) == id(b)

列表 | List

列表(list)是很常用的容器,常被看作 Python 中的数组,但实际上【与 C++ 的 vector 类似】。设 lst 是一个列表:

基础操作

  • 定义列表:lst = [a, b, c, d] ,其中 a,b,c,d 等是列表的元素,类型可以不同
  • 构造空列表:直接写 []list()
  • 打印列表:print(lst)(会将列表中的元素列出,括在方括号里)
  • 访问元素:lst[3] , 下标从 0 开始。此外,还支持负数索引,-1 表示倒数第一个,-2 倒数第二个【与 C 不同】

修改、添加、删除元素

  • 修改:直接访问元素并赋值
  • lst.append(x):在列表末尾添加元素 x
  • lst1.extend(lst2):在列表末尾拼接另一个列表,也可以用运算符 +=
  • lst.insert(idx, x):在列表索引 idx 处插入一个元素 x (插入后,x 的索引是 idx,其后的元素后移一格)
  • del lst[3]:删除指定元素(删除后,其后元素前移一格)
  • lst.pop():弹出并返回最后一个元素
  • lst.pop(idx):弹出并返回指定元素
  • lst.remove(x):删除第一个值为 x 的元素

组织列表

  • lst.sort()lst.sort(reverse = True):对列表排序,永久性修改顺序
  • sorted(lst)sorted(lst, reverse = True):返回排序后的列表,但不改变列表原有顺序
  • lst.reverse():翻转列表,永久性修改顺序
  • len(lst):返回列表长度,即元素个数(不论类型)

遍历列表

  • 从头到尾遍历列表:for i in lst: 循环表达式,【与 C 不同】i 是列表元素,不是索引;循环结束后 i 停留为最后一个元素

  • 遍历列表时同时遍历下标:for idx, value in enumerate(lst):

  • 若要检查列表是否为空,可以用 if lst: 条件表达式,返回 bool

列表切片

  • lst[l:r]:返回一个列表,元素依次是 lst 列表的索引在左闭右开区间内的元素,省略 lr 则默认从头开始或到尾结束
  • lst[l:r:step]:指定步长为 step 切片,step 为 -1 时返回倒序,省略参数后写作 lst[::-1]
  • 可以用循环遍历列表切片:for i in lst[l:r]:
  • 复制列表:在切片中同时省略 lr,即返回从头到尾的列表,如 lst2 = lst1[:],而非 lst2=lst1,后者lst1lst2 实质是同一个列表【类似 C 的引用】

元组 | Tuple

元组就是元素值不可修改(弱意义上的,其中元素的元素可以被修改)的列表。设 tpl 是一个元组:

基础操作

  • 定义元组:tpl = (a, b, c, d),把列表定义中的方括号改成圆括号 () 即可
  • 定义时的小括号有时候可以省略,可以直接用 , 逗号构造元组【与 C 不同,没有逗号运算符】
  • 构造单元组:(1) 会被理解成表达式,要用 (1,)
  • 构造空元组,直接写 ()tuple(),但 (,) 会报错
  • 访问元素:tpl[3] , 下标从 0 开始。

遍历元组

for i in tpl: 和列表一样。

修改元组

元组中元素的值不能修改,但是元组变量本身可以被赋值,这点与字符串类似。此外,如果元组的中的元素是可修改的,如 List,则可以修改 List 内部的元素。

元组解包

经典的 Python 交换赋值代码:a, b = b, a,利用了解包和逗号构造。

其余的若干种解包方法待补充:https://zhuanlan.zhihu.com/p/351369448

元组打包

zip() 函数用于将若干个迭代容器打包为元组(通常是两个 List),返回一个 zip 对象。如果初始 List 的大小不同,则会向最小的对齐。初始的 zip 对象不占内存空间(Python 3.x 新特性),如果要展示,则需手动 list() 转换。

1
2
3
4
5
6
7
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> zipped = list(zip(a,b)) # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(*zipped)) # 与 zip 相反,*zipped 可理解为解包,返回二维矩阵
[(1, 2, 3), (4, 5, 6)]
>>> c, d = zip(*zipped) # 解包后利用逗号构造两个列表

集合 | Set

集合由一组无序、互不重复的元素构成(在数学上也是如此),在内部用哈希实现。设 st 是一个集合:

基础操作

  • 定义集合:st = {1, 2, 3},把列表定义的方括号改成花括号 {} 即可
  • 构造空集合:只能用 set(),因为 {} 的表达被空字典占用了
  • 由列表转集合:st = set([1, 1, 1, 2, 2, 3]),会自动去重,常用于去重列表的遍历 for i in set(lst):
  • 注意集合的元素必须是可 hash 的,不能为 list 这种可变容器变量

添加、删除元素

  • st.add(4):添加一个元素
  • st.remove(2):删除一个元素

字典 | Dictionary

字典是一系列「键值对」,用于存储一组有穷映射,可将任何 Python 对象作为值,【类似于更高端版本的 C++ 的 map】。

基础操作

  • 定义字典:dic = {'name': '张三', 'age': 18}花括号括起一系列键值对,键与值之间冒号 : 分隔,键值对之间逗号 , 分隔。
  • 访问元素:d['name'],用键访问
  • 注意字典的键必须是可 hash 的,不能为 list 或 set 这种可变容器变量,但可以是 tuple

添加、修改、删除

  • 添加:直接赋值即可(即使键本来不存在),如:dic['x'] = 0
  • 修改:dic['age'] = 18,直接赋值即可
  • 删除:del dic['age']

遍历字典

  • 遍历所有键值对:for k, v in dic.items():,其中 items() 返回键值对的列表
  • 遍历所有键:for k in dic.keys():,其中 keys() 返回键的列表,可省略
  • 由于 keys() 的本质是列表,各种对列表的操作也适用,如:for k in sorted(dic.keys()):if 'age' in dic.keys():
  • 遍历所有值:for v in dic.values():,其中 values() 返回值的列表

迭代器

前文提到的所有容器,包括字符串、字节串都是可迭代的,这意味着它们可以用 for 循环来遍历,也可以用生成式构造(下面介绍)。

但最为特殊的迭代器是 range 类型,作为数值列表,与列表有相似之处,但它实际上不占用内存(用于大循环时很节省空间)。下面是一些常用方法:

  • range(l, r):依次生成左闭右开区间中的整数【类似于 C++ 的 for(int i = l; i < r; i++)】,如果省略左端,会默认以 0 开始
  • range(l, r, step):指定步长为 step【类似于 C++ 的 for(int i = l; i < r; i += step)
  • min(range(l, r))max(range(l, r))sum(range(l, r)):返回数值列表的最小值、最大值、总和
  • for i in range(10): 的循环中改变了 i 的值,如 i += 1, 不会影响循环的次数,因为迭代器中的数值列表是不可修改的【与 C 不同】

生成式

使用生成式构造容器是非常常见、高效的操作,下面举几个例子:

  • a = list(range(10)):直接转化数值列表为基本列表
  • lst = [i ** 2 for i in a]:列表生成式
  • st = {x % 7 for x in a}:集合生成式
  • dic = {x ** 2: x for x in a}:字典生成式,保留 : 来分隔键与值
  • tpl = tuple(x + 1 for x in a):元组生成式,直接用 () 会被当成表达式

综上所述,生成式表达可以用三段式:表达式 for 循环变量 in 迭代对象 if 筛选条件,其中最后的筛选条件不一定要。

此外,还可以用更简单的 map() 函数构造容器,其内置了一系列映射句柄,如 map(int, ['1', '2', '3']),或 map(square, [1, 2, 3])

流程控制

Python 中不用大括号来显式地分块,而是用冒号配合缩进(Indent)。代码块与代码块之间至少隔着一个空行表示结束。当一个代码块必须存在,又不想写任何语句的时候,可以写一个 pass 作为占位符。

条件分支

1
2
3
4
5
6
7
a = 1
if a == 1:
print('a is 1')
elif a == 0:
print('a is 0')
else:
print('wtf is a?')

注意,elifelse 后面也要有冒号配合缩进,如果有多个条件,用 andor 逻辑运算符连接。

for 循环

前面所列的容器、数值列表都可以用于 for 循环迭代,比较特别的是字符串也可以迭代:

1
2
3
a = 'hello world'
for c in a:
print(c) # 竖着打印出 hello world,因为 print 自带换行

此外,如果在数值列表的迭代中用不到迭代变量 i,仅作为迭代次数使用,可以用 _ 变量表达。

while 循环

1
2
3
4
a = 10
while 2 <= a < 20: # 语法糖,这种写法是被建议使⽤的
print(a)
a -= 1 # 注意 Python 中没有⾃增 1 和⾃减 1 运算符

跳出循环可以用 breakcontinue【与 C 相同】

异常控制

在 Python 中,我们可以使用 tryexcept 语句来捕获和处理异常。异常处理使我们能够在程序出现错误时执行一些特定的操作,而不是让程序崩溃。下面是基本用法:

1
2
3
4
5
6
7
8
9
10
11
try:
# 可能会引发异常的代码块
except ExceptionType1:
# 处理特定类型的异常,这里需要填入异常类名
except Exception as e:
# 处理未知异常,Exception 是大多数异常类的父类
print("发生了一个未知错误:", e)
else:
# 当没有发生任何异常时执行的代码,例如打印成功信息
finally:
# 无论是否发生异常都会执行的代码,例如文件关闭

注意,如果这里存在 Exception 还无法捕获的异常,例如 KeyboardInterrupt(在命令提示符中如果按下 Ctrl+C 结束终止的键),则可以换成 BaseExpection,这是 Exception 的父类。

另一种常用的方法是循环 try 语句,适用于 API 接口的访问:

1
2
3
4
5
6
7
8
9
10
11
while True:
try:
# 尝试某种操作
pass
# 如果操作成功,跳出循环(如果操作失败则不会执行到 break)
break
except Exception as e:
# 记录异常信息到日志文件
logging.error(f'Error: {e}')
# 等待一段时间后再次尝试
time.sleep(5) # 5秒后重试

函数

基础函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fib(n):
"""
这个函数用于计算斐波那契数 fib(n)
参数:
- n: 需要计算的第 n 个斐波那契数
返回值:
- 第 n 个斐波那契数 fib(n)
"""
current, then = 0, 1
for _ in range(n):
current, then = then, current + then
return current

fib(10) # 调用函数

函数传参

Python 是不允许程序员选择采用传值还是传址的。Python 参数传递采用的肯定是「传对象引用」的方式【类似 C 中传值和传址的结合】。如果函数收到的是一个可变对象(比如 list、dict)的引用,就能修改对象的原始值;如果是一个不可变对象(比如 int、float、str)的引用,就不能直接修改原始对象。

传入参数的数量可以不固定,但是必须指定默认值;也可以调换顺序,但必须指明对象。

1
2
3
4
5
def add_numbers(num1, num2 = 0):
result = num1 + num2
return result
add_numbers(1) # 参数 num2 采用默认 0
add_numbers(b = 2, a = 1) # 调换顺序,指明对象

当然,也可以传递列表等容器,但传递的也是列表的地址,在函数中修改同样会改变原列表,如果不想修改原列表可以用 [:] 传递切片。

传递任意数量的参数

  • 在形参前加星号 *,Python3 会创建一个该形参名称的元组,本质上是一种元组解包
  • 在形参前加双星号 **,Python3 会创建一个该形参名称的字典

返回值

作为动态类型语言,函数返回值可以不固定,可以多个 return 在不同情况下返回不同值,或者没有 return(等价于 return None)。

值得注意的是,Python 中虽然不需要指定参数和返回值的类型,但可以使用类型提示(Type Hints)来在函数定义时体现参数和返回值的类型。这是一种对函数参数和返回值进行注释的方法,它可以增加代码的可读性和可维护性,并提供了一种方便的方式来指定函数的输入和输出类型。

1
2
3
4
5
6
def add_numbers(num1: int, num2: int = 2) -> int:
"""
这个函数用于计算两个整数的和,并返回结果。
"""
result = num1 + num2
return result

函数模块调用

函数可以被存储在模块中被调用,模块是扩展名为 .py 的文件,包含函数的代码【类似于 C 的头文件】

  • 导入整个模块:使用 import pizza 导入,调用时使用 . 句点,如:pizza.make(16, 'green peppers')
  • 导入模块中特定函数:使用 from pizza import make, eat,调用时无需句点,直接用函数名
  • 导入特定函数别名:使用 from pizza import make as mk,调用时无需句点,直接用别名
  • 导入模块中所有函数:使用 from pizza import *,调用时无需句点,但是会污染命名空间,不建议使用

所有 import 都放在程序开头【类似于 C++ 的 #include<>】。

第三方模块

作为一种工具语言,大部分情况我们都是通过「调包」完成任务,即导入第三方库。市面上的第三方库可以通过多种途径获取,包括 pipconda 等。在命令行中使用 pip list 即可查看当前安装的所有库和版本信息,也可以结合管道 pip list | findstr numpy(Windows)。

模块封装

在 Python 的程序模板中经常看见 if __name__ = '__main__',这其实是 Python 中的一种 Magic Method。

Python 中所有 .py 文件都可被视为一个模块,当模块作为脚本被直接运行时,其 __name__ 的值变为 __main__。相反,当模块被其他导入其他脚本运行时,其 __name__ 存放的就是模块的名字(类似环境变量)。

而作为一种解释型语言,Python 会将所有导入的代码全部顺序执行一遍。如果我们在一个脚本中实现了某个算法,想将其作为模块在其他脚本中调用,我们并不希望它在 import 的那一刻就执行,因此,正确的做法是将其封装成函数。

但如果要单独运行该模块,譬如调试功能时,使用 __name__ 就可以完美解决:

1
2
3
4
5
6
def func():
# 这里写函数代码
return

if __name__ = '__main__':
func() # 这里调试函数

Lambda 匿名函数

和很多语言⼀样,Python 中可以使用 Lambda 匿名函数完成一些简单的逻辑,但比较特殊的地方在于,Python 中匿名函数必须只由单个表达式构成,这个表达式的值也就是匿名函数的返回值。

lambda 关键字可以用来创建一个匿名函数,紧跟其后的是参数列表和用冒号 : 分割开的单个表达式。如,lambda x: 2 * x 是将任何输入的数乘 2,而 lambda x, y: x+y 是计算两个数字的和。

使用匿名函数的经验准则是保持简单以及只在本地使用一次。一种常见却不推崇的做法是将其作为简单函数的另一种声明方式,赋值给变量,如:

1
2
3
4
5
>>> doubler = lambda x: 2 * x
>>> doubler(5)
10
>>> type(doubler)
<class 'function'>

对 lambda 函数命名的唯一作用可能是出于教学目的,其问题在于这使得调试不那么直观——错误信息只会提示某个 lambda 函数存在问题,但不会提示哪个函数。

正确的做法应该是将其作为参数传递,如 .sort 函数、sorted 函数等,此时单个表达式会被计算为一个值并且参与后续的计算。

1
2
3
4
5
6
7
8
>>> integers = [(3, -3), (2, 3), (5, 1), (-4, 4)]
>>> sorted(integers, key=lambda x: x[-1])
[(3, -3), (5, 1), (2, 3), (-4, 4)]

>>> nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> nums.sort(key=lambda a: abs(5-a))
>>> nums
[5, 4, 6, 3, 7, 2, 8, 1, 9]

文件操作

open() 函数的第二个实参 w 表示写入(自动创建或覆盖原内容),r 表示只读,a 表示附加(自动创建或添加到文件末尾),r+ 表示读写。如果不加第二个实参,则默认为 r 只读。

读取文件

一种【与 C 相似】的操作是:

1
2
3
4
file = open('temp.txt', 'r')  	# 打开一个文件,返回表示文件的对象
contents = file.read() # 读取整个文件
print(contents)
file.close() # 关闭文件

此外,还有一种更推崇的操作方式,使用 with 上下文管理器,将打开的文件的对象存储在 as 后的变量,这样可以避免由于忘记关闭文件导致丢失数据:

1
2
3
with open('temp.txt', 'r') as file:
contents = file.read()
print(contents)

回到读取本身,方法 read() 读取整个文件的内容并返回单个字符串,并包含每个 \n 换行符。

但实际操作中读入一个长字符串是丑陋而且难以处理的,我们更倾向于逐行读入,用 line.rstrip() 消除行末的 \n

1
2
3
with open('temp.txt', 'r') as file:
for line in file: # file 也可作为一个迭代器
print(line) # 注意每一行末都会有一个 \n 被打印,而 print 本身又自带换行

另一种逐行读入是创建一个包含文件各行内容的列表,每个元素是一行内容的字符串,包含行尾的 \n

1
2
3
with open('temp.txt', 'r') as file:
line1 = file.readline() # 读入第一行作为字符串
lines = file.readlines() # 读入第二行以后的行(文件指针被移动了),作为 List[]

写入文件

1
2
with open('temp.txt', 'w') as file:
file.write("I love programming.\n") # wirte 不会换行,要手动加

方法 write() 表示将字符串写入文件。如果要写入数值,应先用 str() 将其转化为字符串。

同样,按行写入也有对应的函数 writelines(),但要求传入的参数为字符串列表,同时每个字符串后面都要自带换行符,因此比较鸡肋。

如果要追加写入文件,则需要将 w 替换为 a 模式,需要注意的是新文本可能会在旧文本之后立即添加,因此可能需要添加一个换行符 file.write("\n")

当涉及到面向对象编程(Object-Oriented Programming, OOP),Python 提供了类(class)的概念,允许你创建对象、定义属性和方法。

类与对象

在 Python 中,类是创建对象的蓝图。类定义了对象的属性和方法,可以通过实例化(即创建对象)来使用类。下面介绍类与对象的基础用法。

定义类

可以使用 class 关键字来定义一个类。以下是一个简单的类的示例:

1
2
3
4
5
6
class Person:
def __init__(self, name):
self.name = name

def greet(self):
print(f"Hello, my name is {self.name}.")

类包含了一个特殊的方法 __init__,它被称为构造函数(Constructor)。构造函数在创建对象时被调用,并用于初始化对象的属性。在构造函数中,self 是一个特殊的参数,它代表实例化后的对象本身。我们可以使用 self 来引用对象的属性和方法。

创建对象

要创建类的实例(即对象),可以像调用函数一样使用类的名称并传递所需的参数。以下是一个创建 Person 类的对象的示例:

1
person = Person("Alice") # 传递了名为 "Alice" 的参数

访问属性和调用方法

要访问对象的属性和调用对象的方法,可以使用点号 . 运算符。示例:

1
2
print(person.name)  # 输出: Alice
person.greet() # 输出: Hello, my name is Alice.

继承与多态

在面向对象编程中,继承和多态是重要的概念。继承允许创建一个新的类,它从现有的类派生,并继承其属性和方法多态允许子类重写父类的方法,以实现不同的行为。

继承

要创建一个继承自另一个类的子类,可以将父类作为子类定义中的参数。示例:

1
2
3
4
5
6
7
class Student(Person): # 继承的父类作为子类定义中的参数
def __init__(self, name, student_id):
super().__init__(name) # 相当于创建子对象时同时创建一个父对象
self.student_id = student_id

def study(self):
print(f"{self.name} is studying.")

这里定义了一个名为 Student 的子类,它继承自 Person 父类。子类重写了父类的构造函数,并添加了一个名为 student_id 的新属性和一个名为 study 的新方法。使用 super() 函数可以在子类中调用父类的方法

多态

多态允许不同的对象对相同的方法进行不同的实现。示例:

1
2
3
4
5
6
7
8
def introduce(person):
person.greet()

person = Person("Alice")
student = Student("Bob", "12345")

introduce(person) # 输出: Hello, my name is Alice.
introduce(student) # 输出: Hello, my name is Bob.

在上面的示例中,我们定义了一个名为 introduce 的函数,它接受一个 Person 类的对象作为参数,并调用对象的 greet 方法。通过向 introduce 函数传递不同的对象,可以实现多态行为。


Python笔记 #1 基础语法
https://hwcoder.top/Python-Note-1
作者
Wei He
发布于
2021年9月24日
许可协议