Python特殊函数

本文主要介绍Python语言的一些特殊函数、属性、迭代器、生成器,属于Python语言的高级用法,也是真正体现Python语言特点的内容,十分精彩!

基本序列和映射规则

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
def checkIndex(key):
"""
检查索引是否有效,如果不是整型,引发TypeError;如果不是正数,引发IndexError
"""
if not isinstance(key, int): raise TypeError
if key < 0: raise IndexError

class ArithmeticSequence:
def __init__(self, start=0, step=1):
"""
构造函数,当一个对象被创建后,会立即调用该方法
初始化算术序列

起始值——序列中的第一个值
步长——两个相邻数之间的差
"""
self.start = start
self.step = step
self.changed = {}

def __getitem__(self, key):
"""
从序列中取值
"""
checkIndex(key)

try: return self.changed[key] #是否修改了
except KeyError:
return self.start + key*self.step #计算值

def __setitem__(self, key, value):
"""
修改序列中的一项
"""
checkIndex(key)
self.changed[key] = value
1
2
s = ArithmeticSequence(1,2)
s[4] # 自动调用对象s中的__getitem__函数
9
1
2
s[4]=2 # 自动调用对象s中的__setitem__函数
s[4]
2
1
s['four'] #触发TypeError
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-7-f34801bc947b> in <module>()
----> 1 s['four']


<ipython-input-3-98492fefb016> in __getitem__(self, key)
     23         从序列中取值
     24         """
---> 25         checkIndex(key)
     26 
     27         try: return self.changed[key] #是否修改了


<ipython-input-3-98492fefb016> in checkIndex(key)
      3     检查索引是否有效,如果不是整型,引发TypeError;如果不是正数,引发IndexError
      4     """
----> 5     if not isinstance(key, int): raise TypeError
      6     if key < 0: raise IndexError
      7 


TypeError: 
1
s[-2] # 触发IndexError
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-8-59e44d726fda> in <module>()
----> 1 s[-2]


<ipython-input-3-98492fefb016> in __getitem__(self, key)
     23         从序列中取值
     24         """
---> 25         checkIndex(key)
     26 
     27         try: return self.changed[key] #是否修改了


<ipython-input-3-98492fefb016> in checkIndex(key)
      4     """
      5     if not isinstance(key, int): raise TypeError
----> 6     if key < 0: raise IndexError
      7 
      8 class ArithmeticSequence:


IndexError: 

子类化

除了上面定义这几个基本的序列/映射规则方法(4个方法)外(还有__del__和__iter__),也可以继承內建类型(如列表、字典)

1
2
3
4
5
6
7
class CounterList(list):
def __init__(self, *args):
super(CounterList, self).__init__(*args) # 超类方法,直接继承超类的初始化方法,可以同时继承多个超类
self.counter = 0
def __getitem__(self, index):
self.counter += 1
return super(CounterList, self).__getitem__(index)
1
2
3
c = CounterList(range(10))
print(c[4],c[5])
print(c.counter) # 被调用了两次
4 5
2

property函数

对象的属性一般是通过访问函数获取或者设置,如果有多个属性的时候,不仅需要记住访问函数的名字,而且需要记住所有的属性名称,使用起来不方便。这个问题可以通过property函数解决

1
2
3
4
5
6
7
8
9
10
class Rectange:
def __init__(self):
self.width = 0
self.height = 0
def setSize(self, size):
self.width, self.height = size
def getSize(self):
return self.width, self.height
size = property(getSize, setSize) # 直接将取值函数、设置函数作为property函数的两个参数
# 实际上,该函数包括4个参数,具体参看帮助文档
1
2
3
r = Rectange()
r.size = 150,100
print(r.size, r.width, r.height)
(150, 100) 150 100

迭代器对象

在for循环中,前面只讨论对对序列字典进行迭代。实际上,任何对象,只要实现了\(__iter__\)方法,该对象也可以在for中迭代。迭代规则相比列表来讲: 1. 不需要占用很多内存,一个一个计算; 2. 使用迭代器更通用、更简单、更优雅。

1
2
3
4
5
6
7
8
9
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __next__(self): # 必须具有__next__方法
self.a, self.b = self.b, self.a+self.b
return self.a
def __iter__(self):
return self
1
2
3
4
5
fibs = Fibs()
for f in fibs:
if f > 1000:
print (f)
break
1597
1
2
3
#內建函数iter可以将可迭代对象转换为迭代器
it = iter([1, 2, 3])
print(next(it),next(it)) # 调用next函数返回它的下一个值
1 2
1
2
3
4
5
6
7
8
9
# 迭代器也可以转化为序列
class TestIterator:
value = 0 #也可以直接初始化
def __next__(self):
self.value += 1 # 递增属性value
if self.value > 10: raise StopIteration
return self.value
def __iter__(self):
return self
1
2
ti = TestIterator()
list(ti) # 将迭代器转化为序列
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成器函数

  • 循环生成器/生成器推导式和列表推导式的区别
1
2
3
g = (i**2 for i in range(2,5)) #相对列表推导式,增加圆括号,输出一个迭代器
print(next(g),next(g),next(g))
print(sum(i**2 for i in range(2,5))) #可以直接在当前圆括号内使用
4 9 16
29
1
[i**2 for i in range(2,5)] # 列表推导式
[4, 9, 16]
  • 递归生成器 > 关键字yeild每次产生一个值,函数冻结,等待唤醒,唤醒后从停止的那点开始执行
1
2
3
4
5
6
7
8
9
10
def flatten(nested):
try:
try: nested + '' #如果不是字符串,则会出发TypeError
except TypeError: pass #不是字符串,通过检查
else: raise TypeError #是字符串,传递错误信息TypeError
for sublist in nested:
for element in flatten(sublist):
yield element #输出生成器
except TypeError:
yield nested #是字符串,直接输出
1
list(flatten(['bar','zoo',[1,[2,3]]]))
['bar', 'zoo', 1, 2, 3]
1
['bar','zoo',[1,[2,3]]]+''
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-72-af92cc690507> in <module>()
----> 1 ['bar','zoo',[1,[2,3]]]+''


TypeError: can only concatenate list (not "str") to list
  • 生成器方法
1
2
3
4
def repeater(value):
while True:
new = (yield value)
if new is not None: value = new
1
2
3
r = repeater(42)
next(r)
r.send("Hello, world!")
'Hello, world!'
1
2
r = repeater(42)
r.send("new") # 必须要在生成器挂起的时候才可以发送信息,也就是在yield第一次执行之后。
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-91-1af8ac817cac> in <module>()
      1 r = repeater(42)
----> 2 r.send("new") # 必须要在生成器挂起的时候才可以发送信息,也就是在yield第一次执行之后。


TypeError: can't send non-None value to a just-started generator
  • 生成器的替代方法
1
2
3
4
5
6
7
8
9
10
11
12
def flatten(nested):
result = []
try:
try: nested + '' #如果不是字符串,则会出发TypeError
except TypeError: pass #不是字符串,通过检查
else: raise TypeError #是字符串,传递错误信息TypeError
for sublist in nested:
for element in flatten(sublist):
result.append(element) #输出生成器
except TypeError:
result.append(nested) #是字符串,直接输出
return result
1
list(flatten(['bar','zoo',[1,[2,3]]]))
['bar', 'zoo', 1, 2, 3]

参考资料

  1. Magnus Lie Hetland著,司维等人译,Python基础教程(第2版),2017
1
2