【Python】一些PEP提案(一):列表生成式、字典生成式、迭代器、枚举、布尔值
PEP这玩意有点类似C++各个编译器厂商给标准委员会的提案,但比起C++,显然兼容性包袱低的Python的提案更加大胆,很多居然成为了标准。
PEP这玩意有点类似C++各个编译器厂商给标准委员会的提案,但比起C++,显然兼容性包袱低的Python的提案更加大胆,很多居然成为了标准。
PEP 202 – List Comprehensions,列表生成式
形如:
>>> print [i for i in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
的形式,减少了map的使用,可以很方便地构造新的list。
就是这几个嵌套for的语法有点迷惑:
>>> print [(i, f) for i in nums for f in fruit]
[(1, 'Apples'), (1, 'Peaches'), (1, 'Pears'), (1, 'Bananas'),
(2, 'Apples'), (2, 'Peaches'), (2, 'Pears'), (2, 'Bananas'),
(3, 'Apples'), (3, 'Peaches'), (3, 'Pears'), (3, 'Bananas'),
(4, 'Apples'), (4, 'Peaches'), (4, 'Pears'), (4, 'Bananas')]
>>> print [(i, f) for i in nums for f in fruit if f[0] == "P"]
[(1, 'Peaches'), (1, 'Pears'),
(2, 'Peaches'), (2, 'Pears'),
(3, 'Peaches'), (3, 'Pears'),
(4, 'Peaches'), (4, 'Pears')]
>>> print [(i, f) for i in nums for f in fruit if f[0] == "P" if i%2 == 1]
[(1, 'Peaches'), (1, 'Pears'), (3, 'Peaches'), (3, 'Pears')]
都写得这么复杂了,还是单独取出来吧。。。。。。
PEP 274 – Dict Comprehensions,字典生成式
和上面的语法类似,只不过外壳换成了花括号,循环体换成了用冒号连接的键值对:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
通过这种办法可以快速构造一个字典。
PEP 234 – Iterators,迭代器
编程语言的官方中文真是任重道远,这东西用英文表达比用中文容易多了。
iter
对于某个对象来说,只要该对象拥有__iter__
方法(或者说重写了__iter__
方法/Java,拥有__iter__
特征/Rust),就是一个Iterable
对象(一般翻译为[可迭代对象])。某种意义上来说,一个对象是可迭代的,意味着可以当成一个“数组”来处理。
遗憾的是,我没有找到一个只是可迭代的对象,没有实现迭代器(__next__
),或者生成器(yield
)的示例。似乎这个语法一定要配合这两个才能使用。
next
对于某个可迭代对象来说,只要该对象拥有__next__
方法,该对象就是一个Iterator
(一般翻译为[迭代器对象])。用如其名,这意味着当你拿到对象的某个迭代器,你可以马上获取下一个(或者下一个不可达)
以斐波那契数列为例:
class Fib:
def __init__(self, max):
self.a = 0
self.b = 1
self.max = max
def __iter__(self):
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib
fib = Fib(5)
for i in fib:
print(i)
注意__next__
需要内部判断迭代上限,并抛出StopIteration
异常。
另外,对于我此处的代码,迭代行为会修改对象的成员,这意味着如果我想再迭代一次,我就得创建一个新对象。
PEP 279 – The enumerate () built-in function,enumerate 枚举
翻译为“枚举”不是很恰当,因为Python里真的有枚举这玩意。而这个函数和Python的枚举没有半毛钱关系。。。
官方文档提供了内部的接口:
def enumerate(collection):
'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...'
i = 0
it = iter(collection)
while 1:
yield (i, it.next())
i += 1
可以看出来enumerate接收一个迭代器对象,并在调用时生成一个tuple,第一个元素是索引,第二个是迭代器本身返回的元素。
使用的话,也很简答:
for index, ele in enumerate(fib):
print(index, ele)
PEP 285 – Adding a bool type,布尔值
Strong and bitter words indicate a weak cause. 看PEP的文档还挺有意思的。
说起来 iso646.h
还引入了(你不需要 include 这个文件也可以让这个特性生效)and
、not
和or
,作为&&
、!
和||
的可选替代。并非C语言标准委员会想让语言更易于理解,单纯是为了兼容有些键盘上没有这些符号的场景。。。。。。
布尔值的引入本身没有太大问题,现代编程语言终究要走到这一步的,C++也是如此。
另外,当我在网上查资料编写这篇文章时,我读到了一篇很好的文章https://mp.weixin.qq.com/s/YQbk0smMTCexsi3Ytd2AzA,不过作者的说法有点偏激了。至少我觉得他不了解C/C++。下面相关的内容是关于这篇文章的,如果你不想读,可以跳过。
内存复用
如果你学过Java,你对内存复用的设计应该不陌生。简单来说就是 满足一定要求的字符串或者数字,新创建时并不会新分配内存,而是复用已有的内存。 以Python为例子:
Python 对 -5
到 256
之间的整数对象进行缓存(在命令行Python下不一定生效):
a = 100
b = 100
print(f"id(a) = {id(a)}")
print(f"id(b) = {id(b)}")
c = 3000
d = 3000
print(f"id(c) = {id(c)}")
print(f"id(d) = {id(d)}")
然而在我的环境上,打印出来的id似乎是一模一样的:
id(a) = 139857353119184
id(b) = 139857353119184
id(c) = 139857351916560
id(d) = 139857351916560
百思不得其解。
Python 对符合标识符规则的字符串(仅包含字母、数字、下划线)进行驻留:
s1 = "hello"
s2 = "hello"
print(id(s1))
print(id(s2))
s3 = "hello!@SSSSSSSVVVVV))2222" # 包含非标识符字符,不驻留
s4 = "hello!@SSSSSSSVVVVV))2222"
print(id(s3))
print(id(s4))
图中打印出来的id也不符合上面的规则:
139637337804912
139637337804912
139637337867568
139637337867568
想来Python的解释器还进行了其他优化。
C++倒是没有内存驻留这种设计,事实上对于常量来说,可以使用#define
进行宏定义,或者使用constexpr
进行修饰,这两种做法都会使得在编译期,编译器会逐个对代码中出现常量的地方进行文本替换。
返回对象的字符串表示
优秀的设计。本质上是提供了语言级别的接口来打印类的信息,类本身只需要实现接口就好。示例代码如下:
class Worker:
def __str__(self) -> str:
return "Worker"
def __repr__(self) -> str:
return "[DEBUG] Worker"
worker = Worker()
print(worker) # 或者 print(str(worker))
print(repr(worker))
打印如下:
Worker
[DEBUG] Worker
C++也可以重载operator<<
来实现类似的功能,但据我所知的日志库都没用这玩意(官方新版的f-string
就更没用了)
布尔泛化
将布尔值作为整数的子集并非Python首创,这一设计实际上来自C,而Python这样设计布尔值很大程度上也是考虑和C的兼容性。但是Python的另一个布尔泛化的设计就十分优秀了。
C/C++绝大多数变量也可以作为布尔值进行if
判断,但这种判断效果很有限:
0
转换为false
,非零转换为true
nullptr
/NULL
转换为false
,非空指针转换为true
- 对于其他的变量大部分都是
true
Python的判断就比较多了,明确为 False 的对象:
- 布尔类型本身:
False
- 数值类型:
0
(整数、浮点数、复数) - 空容器:
[]
(列表)、{}
(字典)、()
(元组)、''
(字符串)、set()
(集合) - 特殊对象:
None

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)