Python 新特性
3.8
"""
新特性1:海象运算符
"""
a = [1, 2, 3, 4, 5, ]
if (n := len(a) )> 5:
print(f"List len is too long ({n} elements, expected <= 10)")
else:
print(f"List len <=5")
"""
新特性2:
1.增加一个 /,使a,b 必须使用位置参数调用,不能使用关键字参数调用
2.c,d 随便
3.e,f 必须使用关键字参数
"""
def test(a, b, /, c, d, *, e, f):
print(f"a={a}, b={b}, c={c}, d={d}, e={e}, f={f}")
3.9
Python 3.9 支持使用 | 和|= 合并映射,这不难理解,因为二者也是并集运算符
使用 | 合并映射
>>> d1 = {'a':1,'b':3 }
>>> d2 = {'a':2,'b':4,'c':6}
>>> d1 | d2
{'a': 2, 'b': 4, 'c': 6}
>>> d1
{'a': 1, 'b': 3}
>>> d1 |= d2
>>> d1 # 就地更新现有映射
{'a': 2, 'b': 4, 'c': 6}
>>>
使用模式匹配处理映射
def get_creators(record: dict) -> list:
match record:
case {'type': 'book', 'api': 2, 'authors': [*names]}: #1 names是一个列表,authors也是一个列表,*names将列表拆包装入authors中
return names
case {'type': 'book', 'api': 1, 'author': name}: #2
return [name]
case {'type': 'book'}: #3
raise ValueError(f'Invalid "book" record:{record!r}')
case {'type': 'movie', 'director': name}: #4
return [name]
case _: #5
raise ValueError(f'Invaild record:{record!r}')
if __name__ == '__main__':
b1 = dict(api=1,author='Douglas Hofstadter',type='book',title='Godel,Escher,Bach')
print(get_creators(b1)) # ['Douglas Hofstadter']
from collections import OrderedDict
b2 = OrderedDict(api=2,type='book',title='Python in a Nutshell',authors='Martelli Ravenscroft Holden'.split())
print(get_creators(b2)) # ['Douglas Hofstadter'] # ['Martelli', 'Ravenscroft', 'Holden']
print(get_creators({'type': 'book', 'pages': 770}))
'''
# out:
Traceback (most recent call last):
File "E:\PyProject\pytestDemo\demo2.py", line 57, in <module>
print(get_creators({'type':'book','pages':770}))
File "E:\PyProject\pytestDemo\demo2.py", line 43, in get_creators
raise ValueError(f'Invalid "book" record:{record!r}')
ValueError: Invalid "book" record:{'type': 'book', 'pages': 770}
'''
print(get_creators('Spam,spam,spam'))
'''
# out:
Traceback (most recent call last):
File "E:\PyProject\pytestDemo\demo2.py", line 69, in <module>
print(get_creators('Spam,spam,spam'))
File "E:\PyProject\pytestDemo\demo2.py", line 47, in get_creators
raise ValueError(f'Invaild record:{record!r}')
ValueError: Invaild record:'Spam,spam,spam'
'''
1.匹配含有'type':'book','api':2,而且'authors'健映射一个序列的映射对象。以列表形式返回序列中的项
2.匹配含有'type':'book','api':1,而且'authors'健映射任何对象的映射对象,以列表形式返回匹配的对象
3.其他含有'type':'book'的映射均无效,抛出ValueError
4.匹配含有'type':'movie',而且'director'映射单个对象的映射对象,以列表形式返回匹配的对象
5.其他匹配对象均无效,抛出ValueError
通过上面案例可以处理半结构化数据(例如JSON记录)
注意模式中健的顺序无关紧要,即使b2是一个OrderDict,也能作为匹配对象
3.10
序列模式匹配
假设你在设计一个机器人,它接受以文字和数值序列的形式发送命令,例如 BEEPER 440 3。经过拆分和解析后,得到的消息['BEEPER',440,3]。可以使用如下的方法处理
这样的消息
def handle_command(self,message):
match message: #1
case ['BEEPER', frequency,times]: #2
self.beep(times,frequency)
case ['NECK',angle]: #3
self.rotate_neck(angle)
case ['LED', ident,intensity]: #4
self.leds[ident].set_brightness(ident,intensity)
case ['LED',ident,red,green,blue]: #5
self.leds[ident].set_color(ident,red,green,blue)
case _: #6
raise InvalidCommand(message)
1.match 关键字后面的表达式是匹配对象,即各个case子句中的模式尝试匹配的数据。
2.这个模式匹配一个含有3个项的序列。第一个必须是字符串‘BEEPER’。第二个项和第三个项任意,依次绑定到变量frequency和times上
3.这个模式匹配任何含有两项,而且第一项为‘NECK’的序列
4.这个模式匹配第一项为'LED',共有3项的序列。如果项数不匹配,Python继续执行下个case子句
5.这个模式也匹配第一项为‘LED’的序列,不过一共有5个项
6.这是默认的case子句,前面所有模式都不匹配时执行。
match/case 与C语言 中的swtich/case 语句很像,但这的只是表象,与swtich相比,match的一大改进是支持析构,这是一种高级的拆包形式
案例2:
metro_areas = [
('Tokyo','JP',36.933,(35.5555585,139.691667)),
('Delhi NCP','IN',21.935,(28.613889,77.208889)),
('Mexico City','MX',20.142,(19.433333,-99.133333)),
('New York-Newark','US',20.104,(40.808611,-74.020386)),
('Sao Paulo','BR',19.649,(-23.547778,-46.635833))
]
def main():
for record in metro_areas:
match record:
case [name,_,_,(lat,lon)] if lon <=0: #1
print(name,lat,lon)
if __name__ == '__main__':
main()
"""
# out:
Mexico City 19.433333 -99.133333
New York-Newark 40.808611 -74.020386
Sao Paulo -23.547778 -46.635833
"""
1.一个case子句由两部分组成,一部分是模式,一部分是使用if 关键字指定的卫语句(guard clause 可选)
一般来说,匹配对象同时满足以下条件方能匹配序列模式
- 匹配对象是序列
- 匹配对象和模式的项数相等
- 对应的项相互匹配,包括嵌套的项
例如:模式[name,,,(lat,lon)] 匹配一个含有4个项的序列,而且最后一个项必须是一个含有两个项的序列。
序列模式可以些成元组或列表,或者任意形式的嵌套元组和列表,使用哪种句法都没有区别,因为在序列模式中,方括号
和圆括号的意思是一样的。上面的案例中,模式写成列表形式,其中嵌套的序列写成元组形式,这样做只是为了避免重复
使用方括号或圆括号
注意:
在match/case 的上下文中,str,bytes,bytearray 实例不作为序列处理
与拆包不同,模式不析构序列以外的可迭代对象(如迭代器)
模式中的任何一部分均可使用as关键字绑定到变量上
case [name,_,_,(lat,lon) as coord]:
=> 可以匹配['Shanghai','CN',24.9,(31.1,121.3)]并设定以下变量:
- name: 'Shanghai'
- lat: 31.1
- lon: 121.3
- coord: (31.3,121.3)
添加类型信息可以让模式更具体
metro_areas = [
('Tokyo', 'JP', 36.933, (35.5555585, 139.691667)),
('Delhi NCP', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('Sao Paulo', 'BR', 19.649, (-23, -46))
]
def main():
for record in metro_areas:
match record:
case [str(name), _, _, (float(lat), float(lon))] if lon <= 0: #lat 只匹配float类型
print(name, lat, lon)
if __name__ == '__main__':
main()
"""
Mexico City 19.433333 -99.133333
New York-Newark 40.808611 -74.020386
"""
case [str(name), _, _, (float(lat), lon)],在模式上下文中,这种句法的作用是在运行时检查类型。前面的模式将匹配一个4项序列,其中第一个
必须是字符串,第四项必须是一对浮点数。而且第一项中的字符串将绑定到name变量上,第四项中的一对浮点数将分别绑定到lat和lon两个变量上
如果想要匹配任何一个以字符串开头,以嵌套两个浮点数的序列结尾的序列,可以使用如下模式:
case [str(name),_*,(float(lat),float(lon))]
_ 匹配任意数量的项,而且不绑定变量。
如果把_,更换为*extra,匹配的零项或多项将作为列表绑定到extra变量上
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/15840933.html