Python 进阶
2-1 迭代器与生成器
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器
```python
e.g.1
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
print (next(it)) # 输出迭代器的下一个元素
1
print (next(it))
2e.g.2
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:print (x, end=" ")
e.g.3
import sys # 引入 sys 模块
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象while True:
try: print (next(it)) except StopIteration: sys.exit()
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
## 1. 迭代器的创建
- 把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
- __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
- __next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
- e.g.
- ```python
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
2. Stoplteration
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
e.g.
```python
class MyNumbers:
def iter(self):self.a = 1 return self
def next(self):
if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)for x in myiter:
print(x)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
## 3. 生成器
- 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
- 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
- 调用一个生成器函数,返回的是一个迭代器对象。
- e.g.
- ```python
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
2-2 函数
- 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
1. 函数的定义
规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号 : 起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
语法:
1 | def 函数名(参数列表): |
2. 参数传递
python 函数的参数传递:
- 不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
- 可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
3. 参数
以下是调用函数时可使用的正式参数类型:
- 必需参数、关键字参数、默认参数、不定长参数
1)必须参数
- 必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
1 | #可写函数说明 |
2) 关键字参数
- 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
- 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
1 | #可写函数说明 |
3) 默认参数
- 调用函数时,如果没有传递参数,则会使用默认参数。
1 | #可写函数说明 |
4) 不定长参数
- 你可能需要一个函数能处理比当初声明时更多的参数。
- 加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
1 | # 可写函数说明 |
- 还有一种就是参数带两个星号 **,参数会以字典的形式导入。
1 | # 可写函数说明 |
- 声明函数时,参数中星号 * 可以单独出现,后参数要求为关键字形参
1 | def f(a,b,*,c): |
5)匿名函数
Python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
1 | # 语法 |
- 可以将匿名函数封装在一个函数内,这样可以使用同样的代码来创建多个匿名函数。
1 | def myfunc(n): |
6) 强制位置参数
Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
在以下的例子中,形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 和 f 要求为关键字形参:
1 | def f(a, b, /, c, d, *, e, f): |
2-3 输入和输出
1. 输出格式美化
1) str()
- str(): 函数返回一个用户易读的表达形式。
1 | str(1/7) |
2) repr()
repr(): 产生一个解释器易读的表达形式。
```python
s = ‘Hello, Runoob’
repr(s)
“‘Hello, Runoob’”repr() 函数可以转义字符串中的特殊字符
… hello = ‘hello, runoob\n’
hellos = repr(hello)
print(hellos)
‘hello, runoob\n’repr() 的参数可以是 Python 的任何对象
… repr((x, y, (‘Google’, ‘Runoob’)))
“(32.5, 40000, (‘Google’, ‘Runoob’))”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
### 3)just() / zfill()
- rjust() / ljust() / center()
- 字符串靠右/左/居中, 并在填充空格对齐
- zfill()
- 在数字的左边填充 0
### 4) str.format()
```python
>>> print('{1} 和 {0}'.format('Google', 'Runoob'))
Runoob 和 Google
>>> print('站点列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob', other='Taobao'))
站点列表 Google, Runoob, 和 Taobao。
# !a (使用 ascii()), !s (使用 str()) 和 !r (使用 repr()) 可以用于在格式化某个值之前对其进行转化
>>> print('常量 PI 的值近似为: {}。'.format(math.pi))
常量 PI 的值近似为: 3.141592653589793。
>>> print('常量 PI 的值近似为: {!r}。'.format(math.pi))
常量 PI 的值近似为: 3.141592653589793。
# 在 : 后传入一个整数, 可以保证该域至少有这么多的宽度
>>> table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
>>> for name, number in table.items():
... print('{0:10} ==> {1:10d}'.format(name, number))
...
Google ==> 1
Runoob ==> 2
Taobao ==> 3如果你有一个很长的格式化字符串, 而你不想将它们分开, 那么在格式化时通过变量名而非位置会是很好的事情。
- ```python
最简单的就是传入一个字典, 然后使用方括号 [] 来访问键值 :
table = {‘Google’: 1, ‘Runoob’: 2, ‘Taobao’: 3}
print(‘Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}’.format(table))
Runoob: 2; Google: 1; Taobao: 3也可以通过在 table 变量前使用 ** 来实现相同的功能:
table = {‘Google’: 1, ‘Runoob’: 2, ‘Taobao’: 3}
print(‘Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}’.format(**table))
Runoob: 2; Google: 1; Taobao: 31
2
3
4
5
6
7
8
### 5) 旧式字符串格式化
- **%** 操作符也可以实现字符串格式化。 它将左边的参数作为类似 **sprintf()** 式的格式化字符串, 而将右边的代入, 然后返回格式化后的字符串
```python
>>> print('常量 PI 的值近似为:%5.3f。' % math.pi)
常量 PI 的值近似为:3.142。
- ```python
2. 读取键盘输入
- Python 提供了 input() 内置函数从标准输入读入一行文本,默认的标准输入是键盘
1 | str = input("请输入:"); |
2-4 读和写文件
- open() 将会返回一个 file 对象
open(filename, mode)
- filename:包含了你要访问的文件名称的字符串值。
- mode:决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)。
不同模式打开文件的完全列表:
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
模式 | r | r+ | w | w+ | a | a+ |
---|---|---|---|---|---|---|
读 | + | + | + | + | ||
写 | + | + | + | + | + | |
创建 | + | + | + | + | ||
覆盖 | + | + | ||||
指针在开始 | + | + | + | + | ||
指针在结尾 | + | + |
1) 文件对象的方法
f.read()
- 读取一个文件的内容,调用 f.read(size), 这将读取一定数目的数据, 然后作为字符串或字节对象返回
- size 是一个可选的数字类型的参数。
- 当 size 被忽略了或者为负, 那么该文件的所有内容都将被读取并且返回。
1 | # 打开一个文件 |
f.readline
- f.readline() 会从文件中读取单独的一行。换行符为 ‘\n’。
- f.readline() 如果返回一个空字符串, 说明已经已经读取到最后一行。
1 | # 打开一个文件 |
f.readlines
- f.readlines() 将返回该文件中包含的所有行。
- 如果设置可选参数 sizehint, 则读取指定长度的字节, 并且将这些字节按行分割。
1 | # 打开一个文件 |
1 | # 打开一个文件 |
f.write()
- f.write(string) 将 string 写入到文件中, 然后返回写入的字符数。
1 | # 打开一个文件 |
- 如果要写入一些不是字符串的东西,那么需要先进行转换。
f.tell()
- f.tell() 返回文件对象当前所处的位置, 它是从文件开头开始算起的字节数。
f.seek()
- 如果要改变文件当前的位置, 可以使用 f.seek(offset, from_what) 函数
- from_what 的值, 如果是 0 表示开头, 如果是 1 表示当前位置, 2 表示文件的结尾
- seek(x,0) : 从起始位置即文件首行首字符开始移动 x 个字符
- seek(x,1) : 表示从当前位置往后移动x个字符
- seek(-x,2):表示从文件的结尾往前移动x个字符
- from_what 的值, 如果是 0 表示开头, 如果是 1 表示当前位置, 2 表示文件的结尾
1 | open('/tmp/foo.txt', 'rb+') f = |
f.close()
- 在文本文件中 (那些打开文件的模式下没有 b 的), 只会相对于文件起始位置进行定位。
- 当你处理完一个文件后, 调用 f.close() 来关闭文件并释放系统的资源,如果尝试再调用该文件,则会抛出异常。
1 | f.close() |
- 当处理一个文件对象时, 使用 with 关键字是非常好的方式。在结束后, 它会帮你正确的关闭文件。 而且写起来也比 try - finally 语句块要简短
1 | with open('/tmp/foo.txt', 'r') as f: |
2) pickle 模块
- python的pickle模块实现了基本的数据序列和反序列化。
- 能够实现任意对象与文本之间的相互转化,也可以实现任意对象与二进制之间的相互转化
- 提供函数:
- dumps():将 Python 中的对象序列化成二进制对象,并返回;
- loads():读取给定的二进制对象数据,并将其转换为 Python 对象;
- dump():将 Python 中的对象序列化成二进制对象,并写入文件;
- load():读取指定的序列化数据文件,并返回对象。
- dumps 和 loads 实现基于内存的 Python 对象与二进制互转;
- dump 和 load 实现基于文件的 Python 对象与二进制互转。
pickle.dumps()
- 此函数用于将 Python 对象转为二进制对象,其语法格式如下:
dumps(obj, protocol=None, *, fix_imports=True)
此格式中各个参数的含义为:
- obj:要转换的 Python 对象;
- protocol:pickle 的转码协议,取值为 0、1、2、3、4,其中 0、1、2 对应 Python 早期的版本,3 和 4 则对应 Python 3.x 版本及之后的版本。未指定情况下,默认为 3。
- 其它参数:为了兼容 Python 2.x 版本而保留的参数,Python 3.x 中可以忽略。
1 | import pickle |
pickle.loads()
此函数用于将二进制对象转换成 Python 对象,其基本格式如下:
loads(data, *, fix_imports=True, encoding='ASCII', errors='strict')
1 | import pickle |
- 在使用 loads() 函数将二进制对象反序列化成 Python 对象时,会自动识别转码协议,所以不需要将转码协议当作参数传入
pickle.dump()
此函数用于将 Python 对象转换成二进制文件,其基本语法格式为:
dump (obj, file,protocol=None, *, fix mports=True)
其中各个参数的具体含义如下:
- obj:要转换的 Python 对象。
- file:转换到指定的二进制文件中,要求该文件必须是以”wb”的打开方式进行操作。
- protocol:和 dumps() 函数中 protocol 参数的含义完全相同,因此这里不再重复描述。
- 其他参数:为了兼容以前 Python 2.x版本而保留的参数,可以忽略。
1 | import pickle |
pickle.load()
此函数和 dump() 函数相对应,用于将二进制对象文件转换成 Python 对象。该函数的基本语法格式为:
load(file, *, fix_imports=True, encoding='ASCII', errors='strict')
其中,file 参数表示要转换的二进制对象文件(必须以 “rb” 的打开方式操作文件),其它参数只是为了兼容 Python 2.x 版本而保留的参数,可以忽略。
1 | import pickle |
2-5 File(文件)方法
1) open()方法
用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError
- 使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法
open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。
1
open(file, mode='r')
- 完整的语法格式为:
1
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数说明:
file: 必需,文件路径(相对或者绝对路径)。
mode: 可选,文件打开模式
buffering: 设置缓冲
encoding: 一般使用utf8
errors: 报错级别
newline: 区分换行符
closefd: 传入的file参数类型
opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
mode 参数
模式 | 描述 |
---|---|
t | 文本模式 (默认)。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
U | 通用换行模式(Python 3 不支持)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
- 默认为文本模式,如果要以二进制模式打开,加上
b
。
2) file 对象
file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数:
序号 | 方法及描述 |
---|---|
1 | file.close()关闭文件。关闭后文件不能再进行读写操作。 |
2 | file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
3 | file.fileno()返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。 |
4 | file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。 |
5 | file.next()Python 3 中的 File 对象不支持 next() 方法。返回文件下一行。 |
6 | file.read([size])从文件读取指定的字节数,如果未给定或为负则读取所有。 |
7 | file.readline([size])读取整行,包括 “\n” 字符。 |
8 | file.readlines([sizeint])读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。 |
9 | file.seek(offset[, whence])移动文件读取指针到指定位置 |
10 | file.tell()返回文件当前位置。 |
11 | file.truncate([size])从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。 |
12 | file.write(str)将字符串写入文件,返回的是写入的字符长度。 |
13 | file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。 |
2-6 OS文件/ 目录方法
2-7 错误和异常
1. 异常处理
1) try/except
1 | while True: |
try 语句按照如下方式工作;
- 首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)。
- 如果没有异常发生,忽略 except 子句,try 子句执行后结束。
- 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。
- 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组
- ```python
except (RuntimeError, TypeError, NameError):pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 最后一个except子句可以忽略异常的名称,它将被当作通配符使用。你可以使用这种方法打印一个错误信息,然后再次把异常抛出。
- ```python
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
- ```python
2) try/except…else
使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到,而 except 又无法捕获的异常。
```python
def this_fails():
x = 1/0
try:
this_fails() except ZeroDivisionError as err: print('Handling run-time error:', err)
Handling run-time error: int division or modulo by zero
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
### 3) try/finally
![img](https://s2.loli.net/2022/04/17/Pe8ak6xZ1pMfgYK.png)
- finally 语句无论异常是否发生都会执行
- ```python
try:
runoob()
except AssertionError as error:
print(error)
else:
try:
with open('file.log') as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
finally:
print('这句话,无论异常是否发生都会执行。')
2. 抛出异常
使用 raise 语句抛出一个指定的异常。
raise语法格式如下:
raise [Exception [, args [, traceback]]]
```python
x = 10
if x > 5:raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
输出
Traceback (most recent call last):
File “test.py”, line 3, inraise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
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
# 2-8 面向对象
## 1. 面向对象技术简介
- 概念
- **类(Class):** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- **方法:**类中定义的函数。
- **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- **数据成员:**类变量或者实例变量用于处理类及其实例对象的相关的数据。
- **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- **局部变量:**定义在方法中的变量,只作用于当前实例的类。
- **实例变量:**在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- **实例化:**创建一个类的实例,类的具体对象。
- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
- 和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
- Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
- 对象可以包含任意数量和类型的数据。
## 2. 面向对象操作
### 1) 类定义/对象
```python
class Car():
def __init__(self, make, modle, year):
# self代表类的实例,而非类
self.make = make
self.modle = modle
self.year = year
self.mileage = 0.0
def describe(self):
print("{}年,{}品牌的{}产生了!".format(self.year, self.modle, self.make))
def get_mileage(self):
print("这个车已经跑了{:5}公里!".format(self.mileage))
def set_mileage(self, mileage):
# 对属性修改进行限制
if self.mileage < mileage:
self.mileage = mileage
2) 类继承
1 | # ... |
3) 多继承
1 | class DerivedClassName(Base1, Base2, Base3): |
- 需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
4) 类属性与方法
- 类的私有属性
- __private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs
- 类的私有方法
- __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods
2-9 命名空间和作用域
1. 命名空间(namespace)
- 命名空间(namespace)是从名称到对象的映射,大部分的命名空间都是通过Python字典来实现的
- 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
- 三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
2. 作用域
- 作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
- Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
- 四种作用域:
- L(Local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
- 规则顺序: L –> E –> G –> B。
3. global和nonlocal关键字
修改全局变量(global):
e.g.
```python
num = 1
def fun1():global num # 需要使用 global 关键字声明 print(num) num = 123 print(num)
fun1()
print(num)输出
1
123
1231
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量(nonlocal):
- e.g.
- ```python
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
输出
100
100