Python 为什么如此设计?
大概两年半前,我萌生了要创作一个新的系列文章的想法,也就是“Python为什么”,试图对 Python 的语法及特性提出“为什么”式的问题,以此加深对它的理解,探寻使用技巧、发展演变、设计哲学等话题。
一直以来,我都是一个有着较强问题意识的充满着好奇心的人,擅长于识别出相似东西的差异,并从差异性上发现事物的独特意义。
于是,当将 Python 与其它编程语言作比较时,加上阅读及翻译了一些 PEP 从而积攒了一些素材后,我就得到了很多的小发现。当确认了国内外的技术社区里缺少这方面的文章后,我就更确信了这件事的独特价值。
我当时有个天真的想法,觉得可以按照“十万个为什么”的方式,写出源源不断的文章……
刚开始的 2020 年下半年,我创作力旺盛,写了约 20 篇“Python为什么”系列文章!然而,到了 2021 年,仅有 2 篇!再到 2022 年,也是仅仅 2 篇!!……
时间都去哪儿了?怎么我才稍稍微偷了个懒儿,它就不见了呢?本来计划有不少想写的话题的,怎么拖着拖着就忘了该怎么写了呢……
最近眼看到了年末,我越想越是有些不甘,于是,花了几天时间,好好梳理了下“Python为什么”系列文章,优化了 Github 的介绍内容,准备认真把这个系列重拾起来!
我把之前调查问卷里遗留的问题,以及其它计划要写的话题放在 Issues 跟踪,欢迎大家来提问题/给建议/指导写作/监督催更……
下面放出的是目前系列文章的介绍,恳请喜欢本系列的同学给颗 star 鼓励一下!(内容会不断更新/增长,请以 Github 主页为准。)
如果你在手机微信端阅读,由于链接跳转麻烦,建议你通过这个合集的链接进行阅读。
文章列表
- Python 设计和历史的常见问题
- Python 官方提供了约 30 个常见问题的 FAQ,你可以从中快速得到“权威”的解释
- Python 为什么用 len() 函数,不用 x.len() 风格?
- 介绍了《流畅的Python》及 Guido 的解释
- 我本人认为这体现了 Python 对世界本质的洞察
- 文章顺便回答了:为什么 Python 的索引从 0 开始计数?
- Python 为什么使用缩进来划分代码块?
- 这是个经典的问题,总会被提起,我总结了 8 个原因
- 有不少人对上述 8 个原因并不买账,因此我补充了一个回复:Python 的缩进绝不是反人类的设计!
- Guido 在一次采访中说:严格要求代码缩进确实有点夸张,改用花括号,也不是不可以
- Python 的缩进起源于 ABC,而 ABC 的缩进起源于 60-70 年代的编程畅想
- Python 为什么不用分号作语句终止符?
- 分号一般有分隔符与终止符两种作用,但 Python 只用分号作为分隔符,却不用它作为终止符, 而是改用换行作为终止符。本文精炼总结了 5 个原因
- Python 为什么没有 main 函数?为什么我不推荐写 main 函数?
- main 函数作为某些编程语言的执行入口是强制必要的,然而 Python 这门脚本语言有着自己更为灵活的执行方式
- 在我的编程习惯中,我反感那些不假思索的
if __name__ == '__main__'
写法,文中给出了我的编程建议
- Python 为什么推荐蛇形命名法?
- 编程语言中有好几种变量命名风格,最为流行的两种分别是驼峰命名法和蛇形命名法。本文从编程语言的历史发展过程和语言内部的使用习惯角度,解释了为什么 Python 更偏好于蛇形命名法
- Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?
- 有过 C/C++/Java 等语言的编程经验的开发者会疑惑,为什么 Python 中没有 i++ 这样的语法
- 这个问题反映出 Python 中的数字对象跟其它语言中的数字有着根本性的差异;另外,Python 的可迭代对象特性,也深刻影响着语言的诸多设计方面
- Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?
- 很多人以为“a,b=b,a”(交换变量操作)跟“a,b=1,2”(多变量赋值)一样,都是基于元组解包的特性,然而 CPython 的实现并非如此
- CPython 使用专门的优化指令(即 ROT_TWO、ROT_THREE 和 ROT_FOUR)实现栈顶元素的快捷交换
- 当同时交换的元素数量大于 4 个时,解释器才会跟“a,b=1,2”(多变量赋值)一样,基于解包实现变量赋值
- Python 为什么用 # 号作注释符?
- 注释符是编程语言中最基础的要素之一,Python 属于“# 号注释符阵营”,原因或许是它遵循着 Shell 等脚本语言的传统
- Python 中不存在“块注释符”,Guido 曾建议使用多行字符串(multi-line strings)来达到块注释的效果,但这种方案在语义上有点怪异
- Python 为什么要有 pass 语句?
- pass 是 Python 独有的一种空操作,其它语言并没有这样的设计
- pass 可以作为一种空间占位符,辅助程序员快速编程,然而这点小用途并非至关重要的
- 由于 Python 不使用花括号之类的手段来划分代码块,因此在定义空函数时,pass 就成了一种补齐语法逻辑的方案
- Python 为什么会有个奇怪的“...”对象?
- ... 是 Python3 在 PEP-3100 中引入的一个内置常量,与 Ellipsis 表示同一个对象
- 官方说它们是单例的,然而这有违事实。要么是文档错了,要么这是一个 Bug ?
- ... 有什么用处,能够解决什么问题?文中介绍了 4 个用途:扩展切片语法、表达“未完成的代码”语义、Type Hint 用法、表示无限循环
- Python 为什么能支持任意的真值判断?
- 这也是 Python 与众不同的一个特性,它将其它语言中仅限于布尔类型的操作(if 或 while 或布尔操作 and、or、not),扩展到了任意对象,带来了极大的灵活性
- 真值判断的结果取决于__bool__() 和 __len__() 这两个魔术方法的返回值
- Python 甚至可以对数字对象作真值判断(表示 0 的数为 False,其它数为 True)
- Python 函数为什么会默认返回 None?
- Python 隐性地为没有带 return 的函数添加一个 return 操作,即默认返回 None 值,这是由解释器强行注入的逻辑。这意味着:Python 中不存在无返回值的函数
- 为什么 Python 要强制令所有函数都有一个返回值呢?为什么它不支持无返回值的空函数呢?
- Python 为什么没有 void 关键字?
- void 通常指的是一种类型(type),但是它没有具体的值(value)。文中介绍了其它语言需要使用 void 关键字实现的两种功能
- Python 舍弃了表示“没有值的类型”的 void,统一使用表示“仅有一个值的类型” None,配合前一篇“所有函数必然有返回值”的设计,实现了简单好用的效果
- Python 为什么是强类型语言,不是弱类型语言?
- 动静类型与强弱类型是两组不同维度的概念,不应混为一谈。在编程语言发展的早期,当强弱类型的概念还未提出时,一些大佬使用动静类型来笼统地描述语言的特性,这是历史原因
- 如今主流观点以“隐式类型转换”来划分强弱类型,Python 毫无疑问是强类型语言。文中针对几个易混淆的问题,详细解释了为什么 Python 中不存在“隐式类型转换”
- Python 之父为什么嫌弃 lambda 匿名函数?
- lambda 语法借鉴自 lisp 语言,却遭到 Python 之父的嫌弃,然而它竟从他的屠刀下幸存,这段故事充满戏剧性
- Python 的 lambda 只支持单行表达式,功能不完备。曾有人提议增强 lambda 语法,Python 之父认为那不是好的设计,因而否决了
- Guido 提出要一次性移除 reduce()、map()、filter() 以及 lambda,但最后他妥协了
- Python 为什么不支持 switch 语句?
- 大多数语言都提供了 switch 语句或者极其相似的东西,但在 Python 之父的裁决下,Python 不提供 switch 语句
- 文章介绍了试图引入 switch 语句的 PEP-275 与 PEP-3103,总结了这两个提案的要点以及被否决的原因
- Python 疑难问题:[] 与 list() 哪个快?为什么快?快多少呢?
- 两种创建列表的 [] 与 list() 写法,哪一个更快呢,为什么它会更快呢?
- 文章通过字节码与执行过程的分析,解释了两者执行速度的差异
- 为什么说 Python 内置函数并不是万能的?
- 内置函数的名称并不是关键字,而内置作用域位于名称查找的最低优先级,因此在调用时,某些内置函数/类型的执行速度就明显慢于它们对应的字面量表示法
- 为什么继承 Python 内置类型会出问题?!
- 由《流畅的Python》中的例子,引出 Python 在内置类型子类化时不合常理的话题
- 分析魔术方法的底层实现逻辑及调用关系,解释内置类型存在的问题
- 介绍了内置类型子类化的最佳实践
- 为什么 Python 的 f-string 可以拼接字符串与数字?
- Python 是强类型语言,在不经过强制类型转换的情况下,字符串无法拼接数字
- 介绍了 PEP-498 实现 f-string 的原理
- Python 的切片为什么不会索引越界?
- 切片是不少编程语言的特性,Python 的切片不仅功能完善,而且在使用上更为灵活
- 索引越界是一个常见的问题,Python 切片使用了几条规则,屏蔽了可能导致出错的情况
- 文章介绍了 Python 的解决方案,但是也留下了一个疑问:为什么 Python 的切片语法要允许索引超出边界呢,为什么不设计成抛出索引错误?
- 为什么 range() 生成的不是迭代器?
- 有很多内置方法可以生成迭代器,然而似乎只有 range() 生成的是可迭代对象,这个 range() 显得非常独特。文中给出了我对此的猜想
- 我还注意到 range 是一种不可变序列,然而它跟字符串这种不可变序列相比,也有着独特的表现
- Python 为什么要保留显式的 self ?
- 这也是一个常见问题。这里给出了官方文档的解释,另外附了 Guido 的一篇博客全文
- Python 为什么不设计 do-while 循环结构?
- 在 C/C++、C#、PHP、Java、JavaScript 等语言中,do-while 是一种基本结构。Python 为什么不沿袭它们的传统呢?有什么特殊的考虑?
- 文章列举了其它语言中 do-while 语法的主要使用场景,解释了为什么 Python 可以不用这种结构
- 介绍了 PEP-315 试图引入 do-while 结构的尝试,以及 Guido 的反对意见
- 为什么 Python 3 把 print 改为函数?
- Python3 与 Python2 最显眼的一个区别就是:print 语句变成了 print() 函数
- PEP-3105 Make print a function 是对这个问题最好的回答
- 为什么说 Python 最会变魔术的魔术方法是它?
- __missing__() 是仅在内置类型的子类上才存在的魔术方法,似乎是唯一的特例
- __missing__() 极为特殊,Python 解释器为它开了后门,实现了最为罕见的“魔术方法间调用”逻辑
- Python 为什么用”elif“,而不是“else if”?
- elif 写法相比于“else if”更为简洁,这种写法并非 Python 首创。Guido 发推特解释了这种写法的来源
当在两年半前写下第一篇“Python为什么”系列的时候,我无法想象自己会在 2023 年到来之际写下这一篇宣告重新起航的小结,更无法想象是在下一个两年半,或者五年半或者更久,再次写下一篇新的总结。谁说得准呢!
但是,不忘初心,珍惜当下的决心,树立砥砺前行的恒心,我可以的!
最后,别急着划走啊,请一定记得点个关注、点个 star 哈,喵喵喵~~
Python 为什么如此设计?的更多相关文章
- 《一头扎进》系列之Python+Selenium框架设计篇3- 价值好几K的框架,狼来了,狼来了....,狼没来,框架真的来了
1. 简介 前边宏哥一边一边的喊框架,就如同一边一边的喊狼来了!狼来了!.....这回是狼没有来,框架真的来了.从本文开始宏哥将会一步一步介绍,如何从无到有地创建自己的第一个自动化测试框架.这一篇,我 ...
- 《一头扎进》系列之Python+Selenium框架设计篇4- 价值好几K的框架,呵!这个框架有点意思啊
1.简介 前面文章,我们实现了框架的一部分功能,包括日志类和浏览器引擎类的封装,今天我们继续封装一个基类和介绍如何实现POM.关于基类,是这样定义的:把一些常见的页面操作的selenium封装到bas ...
- 《一头扎进》系列之Python+Selenium框架设计篇5 - 价值好几K的框架,哎呦!这个框架还真有点料啊!!!
1. 简介 其实,到前面这一篇文章,简单的Python+Selenium自动化测试框架就已经算实现了.接下来的主要是介绍,unittest管理脚本,如何如何加载执行脚本,再就是采用第三方插件,实现输出 ...
- 学写PEP,参与Python语言的设计
如果你为Python写了一篇PEP,这篇PEP成功的被Python指导委员会接受了,那么以后你在吹牛皮的时候你就可以说我主导了Python语言某个特性的设计工作. -- 跬蟒 我就问你主导Python ...
- python多线程爬虫设计及实现示例
爬虫的基本步骤分为:获取,解析,存储.假设这里获取和存储为io密集型(访问网络和数据存储),解析为cpu密集型.那么在设计多线程爬虫时主要有两种方案:第一种方案是一个线程完成三个步骤,然后运行多个线程 ...
- 浅析Python解释器的设计
从现代编译器的角度看,解释器和编译器的边界已经相当的模糊.我们后面的讨论说到的编译器就是Python的解释器,没有特别说明的指的是CPython的实现. 内存管理(Memory Management) ...
- Python 的经典设计格言,格言来源于 Python 但不限于 Python
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Si ...
- Python 关于类函数设计的一点总结
关于类函数设计的一点总结 by:授客 QQ:1033553122 代码1 #!/usr/bin/env python #-*-encoding:utf-8-*- __author__ = 'shouk ...
- Python 类的设计原则
# 面向对象遵循的原则: SOLID # S(Single Responsibility Principle) # 单一职责原则 # 一个类只负责一项职责 # 好处 # 易于维护, 写出高内聚的代码 ...
- Python+Selenium框架设计篇之-什么是POM
前面我们介绍了Python中的单元测试框架unittest,以后我们所有的测试类文件,都采用unittest来辅助我们进行debug和脚本开发.搞定了debug机制和确定了unittest来进行创建和 ...
随机推荐
- 小白入行安全圈内必须知道的top10
OWASP Top10 前言 每年的Top10都在更新,但是一般不会有太大的改变,这里说明的是 2021年的Top10排行榜. A01:访问控制失效(Broken Access Control) 攻击 ...
- netstat -lnp |grep XXX后不显示进程
netstat -lnp |grep XXX后不显示进程,不一定是没有进程,可能是这个命令不好使,换成 ps -ef | grep XXX
- SpringMvc(五) - 支付宝沙箱和关键字过滤,md5加密,SSM项目重要知识点
1.支付宝沙箱 1.1 jar包 alipay-sdk <!-- alipay-sdk --> <dependency> <groupId>com.alipay.s ...
- C++ 栈和典型迷宫问题
C++ 栈和迷宫问题 1. 前言 栈是一种受限的数据结构,要求在存储数据时遵循先进后出(Last In First Out)的原则.可以把栈看成只有一个口子的桶子,进和出都是走的这个口子(也称为栈顶) ...
- TensorFlow搭建模型方式总结
引言 TensorFlow提供了多种API,使得入门者和专家可以根据自己的需求选择不同的API搭建模型. 基于Keras Sequential API搭建模型 Sequential适用于线性堆叠的方式 ...
- 聊一聊被 .NET程序员 遗忘的 COM 组件
一:背景 1.讲故事 最近遇到了好几起和 COM 相关的Dump,由于对 COM 整体运作不是很了解,所以分析此类dump还是比较头疼的,比如下面这个经典的 COM 调用栈. 0:044> ~~ ...
- 19.MongoDB系列之批量更新写入Groovy版
Groovy作为脚本,比Java在数据处理中具有更高的灵活性 // 获取mongo连接略 .... def count = 0 for(Township town : townships) { Doc ...
- laravel config()获取null
常规开发获取config值的是否发现获取值为null找了下文档,发现laravel是要把config注册到$app里面. 找到这个目录.加入这一行.就可以了
- el-form-item label中的字体样式设置格式
1.设置前的代码 <el-form-item label="管理员密码" prop="password" > <el-input type=& ...
- .net core-利用PdfSharpCore和SkiaSharp.QrCode 添加PDF二维码页眉
前序 由于去年的一个项目需要在PDF 添加公司二维码 ,当时在网上找了很多操作PDF方案,第一种Aspose.PDF,很遗憾 Aspose.PDF 有添加版权的背景还是页脚我忘记了,不适合公司项目,最 ...