python @any%
Publish on 2022-03-09

Intro

本篇主要 follow 书籍 Fluent Python ,对python的现代优雅实现进行汇总学习,由于语法检查器和python本身的发展,有些书籍中的不足之处或是不到位的地方都会在笔者的Elegant python中进行补充。

None 的静态类型警告

你可能会写出类似以下的代码

def step(context: Context = None):
		context = context or Context.new()
    """
				code snippet
		"""

程序顺利运行了

但是LSP会毫不留情地给你一个错:”Expression of type “None” cannot be assigned to parameter of type [Context]”

你愤懑不平,抱怨LSP是如何迂腐而不智能,连这样简单的代码逻辑都无法理清

但是我们可以

from typing import Union
def step(context: Union[Context, None] = None):
		context = context or Context.new()
    """
				code snippet
		"""

或者

from typing import Optional
def step(context: Optional[Context] = None):
		context = context or Context.new()
    """
				code snippet
		"""

是的,it’s boring but this is the way

Fluent Python

abstract

I don’t like meta class in Python,these shit makes your code unexplicit,which I despise a lot. 除了一些 asyncio 的场景下会对异步元编程进行简单总结,其余的相关内容将跳过。

ch2 序列组成的数组

摘要

作者会将主要精力放在第五、七、八、九章中,运算符的重载等内容对于本人来说实在不算一种优秀的编程习惯。有些人可能很喜欢元编程,但是本人更加青睐函数化,这样更加直观,通过不同的函数命名也会使得代码更加易于维护,而不是通过 tree sitter 去给自己没事找事。观后感不会明确区分章节,只会在思路和概念上进行区分。

列表

Numpy的技巧

在NumPy 中,... 用作多维数组切片的快捷方式。如果 x 是四维数组,那么 x[i, ...] 就是 x[i, :, :, :] 的缩写。

* 来处理多余的元素

  • *运算符可以把一个可迭代对象拆开作为函数的参数
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder
(2, 4)

* 来处理剩下的元素

Python 中,函数用 *args 来获取不确定数量的参数是一种经典写法。 于是 Python 3 里,这个概念被扩展到了平行赋值中:

>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])
>>> a, b, *rest = range(2)
>>> a, b, rest
(0, 1, [])

在平行赋值中,* 前缀只能用在一个变量名前面,但是这个变量可以出现在赋值表达式的任意位置:

>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
>>> *head, b, c, d = range(5)
>>> head, b, c, d
([0, 1], 2, 3, 4)

嵌套结构的元组拆包

metro_areas = [
	('Tokyo','JP',36.933,(35.689722,139.691667)),
	('Delhi NCR', '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)),
]
print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))
fmt = '{:15} | {:9.4f} | {:9.4f}'
for name, cc, pop, (latitude, longitude) in metro_areas:
	if longitude <= 0:
		print(fmt.format(name, latitude, longitude))

namedtuple

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'

创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。

存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意,元组的构造函数却只接受单一的可迭代对象)

可以通过字段名或者位置来获取一个字段的信息。除了从普通元组那里继承来的属性之外,具名元组还有一些自己专有的属性。下面的示例中就展示了几个最有用的:_fields 类属性、类方法 _make(iterable) 和实例方法 _asdict()

>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population',
21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
>>> for key, value in delhi._asdict().items():
print(key + ':', value)
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)

bisect

bisect(haystack, needle)haystack(干草垛)里搜索 needle(针)的位置,该位置满足的条件是,把 needle 插入这个位置之后,haystack 还能保持升序。也就是在说这个函数返回的位置前面

的值,都小于或等于 needle 的值。其中 haystack 必须是一个有序的序列。你可以先用 bisect(haystack, needle) 查找位置 index,再用 haystack.insert(index, needle) 来插入新值。但你也可用 insort 来一步到位,并且后者的速度更快一些。

数组保存与读取的优雅实现

如果我们需要一个只包含数字的列表,那么 array.arraylist 更高效。数组支持所有跟可变序列有关的操作,包括 .pop.insert.extend。另外,数组还提供从文件读取和存入文件的更快的方法,如 .frombytes.tofile

Python 数组跟 C 语言数组一样精简。创建数组需要一个类型码,这个类型码用来表示在底层的 C 语言应该存放怎样的数据类型。比如 b 类型码代表的是有符号的字符(signed char),因此 array('b') 创建出的数组就只能存放一个字节大小的整数,范围从 -128 到 127,这样在序列很大的时候,我们能节省很多空间。而且 Python 不会允许你在数组里存放除指定类型之外的数据。

>>> from array import array
>>> from random import random
>>> floats = array('d', (random() for i in range(10**7)))
>>> floats[-1]
0.07802343889111107
>>> fp = open('floats.bin', 'wb')
>>> floats.tofile(fp)
>>> fp.close()
>>> floats2 = array('d')
>>> fp = open('floats.bin', 'rb')
>>> floats2.fromfile(fp, 10**7)
>>> fp.close()
>>> floats2[-1]
0.07802343889111107
>>> floats2 == floats
True

高阶函数相关

mapfilterreduceallany

Decorator

Just fully read chapter 7.

Coroutine & asyncio

Fully read chapter 14, 16, 17 and 18

© 2024 humbornjo :: based on 
nobloger  ::  rss