15个为什么,帮助你更好的理解Python!

- 点击上方“i小码哥”订阅我吧!-


01. 为什么使用缩进来分组语句?

Guido van Rossum 认为使用缩进进行分组非常优雅,并且大大提高了普通 Python 程序的清晰度。大多数人在一段时间后就学会并喜欢上这个功能。
由于没有开始/结束括号,因此解析器感知的分组与人类读者之间不会存在分歧。偶尔 C 程序员会遇到像这样的代码片段:

   
   
     
     
if (x <= y) x++; y--;z++;
如果条件为真,则只执行   x++  语句,但缩进会使你认为情况并非如此。即使是经验丰富的 C 程序员有时会长时间盯着它,想知道为什么即使  x > y , y  也在减少。
因为没有开始/结束括号,所以 Python 不太容易发生编码式冲突。在 C 中,括号可以放到许多不同的位置。如果您习惯于阅读和编写使用一种风格的代码,那么在阅读(或被要求编写)另一种风格时,您至少会感到有些不安。
许多编码风格将开始/结束括号单独放在一行上。这使得程序相当长,浪费了宝贵的屏幕空间,使得更难以对程序进行全面的了解。理想情况下,函数应该适合一个屏幕(例如,20--30 行)。20 行 Python 可以完成比 20 行 C 更多的工作。这不仅仅是由于缺少开始/结束括号 -- 缺少声明和高级数据类型也是其中的原因 -- 但缩进基于语法肯定有帮助。

02. 为什么简单的算术运算得到奇怪的结果?

请看下一个问题。


03. 为什么浮点计算不准确?

用户经常对这样的结果感到惊讶:


   
   
     
     
>>> 1.2 - 1.0 0.19999999999999996
并且认为这是 Python 中的一个 bug。其实不是这样。这与 Python 关系不大,而与底层平台如何处理浮点数字关系更大。
CPython 中的   float  类型使用 C 语言的  double  类型进行存储。 float  对象的值是以固定的精度(通常为 53 位)存储的二进制浮点数,由于 Python 使用 C 操作,而后者依赖于处理器中的硬件实现来执行浮点运算。这意味着就浮点运算而言,Python 的行为类似于许多流行的语言,包括 C 和 Java。
许多可以轻松地用十进制表示的数字不能用二进制浮点表示。例如,在输入以下语句后:

   
   
     
     
>>> x = 1.2
为  x  存储的值是与十进制的值  1.2  (非常接近) 的近似值,但不完全等于它。在典型的机器上,实际存储的值是:

   
   
     
     
1.0011001100110011001100110011001100110011001100110011 (binary)
它对应于十进制数值:

   
   
     
     
1.1999999999999999555910790149937383830547332763671875 (decimal)
典型的 53 位精度为 Python 浮点数提供了 15-16 位小数的精度。
要获得更完整的解释,请参阅 Python 教程中的 浮点算术 一章。

04. 为什么 Python 字符串是不可变的?

有几个优点。
一个是性能:知道字符串是不可变的,意味着我们可以在创建时为它分配空间,并且存储需求是固定不变的。这也是元组和列表之间区别的原因之一。
另一个优点是,Python 中的字符串被视为与数字一样“基本”。任何动作都不会将值 8 更改为其他值,在 Python 中,任何动作都不会将字符串 "8" 更改为其他值。

05. 异常有多快?

如果没有引发异常,则 try/except 块的效率极高。实际上捕获异常是昂贵的。在 2.0 之前的 Python 版本中,通常使用这个习惯用法:

   
   
     
     
try: value = mydict[key] except KeyError: mydict[key] = getvalue(key) value = mydict[key]
只有当你期望 dict 在任何时候都有 key 时,这才有意义。如果不是这样的话,你就是应该这样编码:

   
   
     
     
if key in mydict: value = mydict[key] else: value = mydict[key] = getvalue(key)
对于这种特定的情况,您还可以使用  value = dict.setdefault(key, getvalue(key)) ,但前提是调用  getvalue() 足够便宜,因为在所有情况下都会对其进行评估。

06. 为什么 Python 中没有 switch 或 case 语句?

你可以通过一系列  if... elif... elif... else. 轻松完成这项工作。对于 switch 语句语法已经有了一些建议,但尚未就是否以及如何进行范围测试达成共识。有关完整的详细信息和当前状态,请参阅  PEP 275  。
对于需要从大量可能性中进行选择的情况,可以创建一个字典,将 case 值映射到要调用的函数。例如:

   
   
     
     
def function_1(...): ...
functions = {'a': function_1, 'b': function_2, 'c': self.method_1, ...}
func = functions[value] func()
对于对象调用方法,可以通过使用  getattr()  内置检索具有特定名称的方法来进一步简化:

   
   
     
     
def visit_a(self, ...): ... ...
def dispatch(self, value): method_name = 'visit_' + str(value) method = getattr(self, method_name) method()
建议对方法名使用前缀,例如本例中的  visit_  。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。

07. 难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?

答案 1:不幸的是,解释器为每个 Python 堆栈帧推送至少一个 C 堆栈帧。此外,扩展可以随时回调 Python。因此,一个完整的线程实现需要对 C 的线程支持。
答案 2:幸运的是, Stackless Python 有一个完全重新设计的解释器循环,可以避免 C 堆栈。

08. 为什么 lambda 表达式不包含语句?

Python 的 lambda 表达式不能包含语句,因为 Python 的语法框架不能处理嵌套在表达式内部的语句。然而,在 Python 中,这并不是一个严重的问题。与其他语言中添加功能的 lambda 表单不同,Python 的 lambdas 只是一种速记符号,如果您懒得定义函数的话。
函数已经是 Python 中的第一类对象,可以在本地范围内声明。因此,使用 lambda 而不是本地定义的函数的唯一优点是你不需要为函数创建一个名称 -- 这只是一个分配了函数对象(与 lambda 表达式生成的对象类型完全相同)的局部变量!

09. 可以将 Python 编译为机器代码,C 或其他语言吗?

Cython 将带有可选注释的 Python 修改版本编译到 C 扩展中。Nuitka 是一个将 Python 编译成 C++ 代码的新兴编译器,旨在支持完整的 Python 语言。要编译成 Java,可以考虑 VOC 。

10. Python 如何管理内存?

Python 内存管理的细节取决于实现。Python 的标准实现 CPython 使用引用计数来检测不可访问的对象,并使用另一种机制来收集引用循环,定期执行循环检测算法来查找不可访问的循环并删除所涉及的对象。 gc  模块提供了执行垃圾回收、获取调试统计信息和优化收集器参数的函数。
但是,其他实现(如 Jython 或 PyPy ),)可以依赖不同的机制,如完全的垃圾回收器 。如果你的 Python 代码依赖于引用计数实现的行为,则这种差异可能会导致一些微妙的移植问题。
在一些 Python 实现中,以下代码(在 CPython 中工作的很好)可能会耗尽文件描述符:

   
   
     
     
for file in very_long_list_of_files: f = open(file) c = f.read(1)
实际上,使用 CPython 的引用计数和析构函数方案, 每个新赋值的  f  都会关闭前一个文件。然而,对于传统的 GC,这些文件对象只能以不同的时间间隔(可能很长的时间间隔)被收集(和关闭)。
如果要编写可用于任何 python 实现的代码,则应显式关闭该文件或使用  with 语句 ;无论内存管理方案如何,这都有效:

   
   
     
     
for file in very_long_list_of_files: with open(file) as f:c = f.read(1)


11. 为什么 CPython 不使用更传统的垃圾回收方案?

首先,这不是 C 标准特性,因此不能移植。(是的,我们知道 Boehm GC 库。它包含了  大多数  常见平台(但不是所有平台)的汇编代码,尽管它基本上是透明的,但也不是完全透明的; 要让 Python 使用它,需要使用补丁。)
当 Python 嵌入到其他应用程序中时,传统的 GC 也成为一个问题。在独立的 Python 中,可以用 GC 库提供的版本替换标准的 malloc()和 free(),嵌入 Python 的应用程序可能希望用  它自己  替代 malloc()和 free(),而可能不需要 Python 的。现在,CPython 可以正确地实现 malloc()和 free()。

12. CPython 退出时为什么不释放所有内存?

当 Python 退出时,从全局命名空间或 Python 模块引用的对象并不总是被释放。如果存在循环引用,则可能发生这种情况 C 库分配的某些内存也是不可能释放的(例如像 Purify 这样的工具会抱怨这些内容)。但是,Python 在退出时清理内存并尝试销毁每个对象。
如果要强制 Python 在释放时删除某些内容,请使用  atexit  模块运行一个函数,强制删除这些内容。

13. 为什么有单独的元组和列表数据类型?

虽然列表和元组在许多方面是相似的,但它们的使用方式通常是完全不同的。可以认为元组类似于 Pascal 记录或 C 结构;它们是相关数据的小集合,可以是不同类型的数据,可以作为一个组进行操作。例如,笛卡尔坐标适当地表示为两个或三个数字的元组。
另一方面,列表更像其他语言中的数组。它们倾向于持有不同数量的对象,所有对象都具有相同的类型,并且逐个操作。例如,  os.listdir('.')  返回表示当前目录中的文件的字符串列表。如果向目录中添加了一两个文件,对此输出进行操作的函数通常不会中断。
元组是不可变的,这意味着一旦创建了元组,就不能用新值替换它的任何元素。列表是可变的,这意味着您始终可以更改列表的元素。只有不变元素可以用作字典的 key,因此只能将元组和非列表用作 key。

14. 列表如何在 CPython 中实现?

CPython 的列表实际上是可变长度的数组,而不是 lisp 风格的链表。该实现使用对其他对象的引用的连续数组,并在列表头结构中保留指向该数组和数组长度的指针。
这使得索引列表  a[i]  的操作成本与列表的大小或索引的值无关。
当添加或插入项时,将调整引用数组的大小。并采用了一些巧妙的方法来提高重复添加项的性能; 当数组必须增长时,会分配一些额外的空间,以便在接下来的几次中不需要实际调整大小。

15. 字典如何在 CPython 中实现?

CPython 的字典实现为可调整大小的哈希表。与 B-树相比,这在大多数情况下为查找(目前最常见的操作)提供了更好的性能,并且实现更简单。
字典的工作方式是使用  hash()  内置函数计算字典中存储的每个键的 hash 代码。hash 代码根据键和每个进程的种子而变化很大;例如,"Python" 的 hash 值为-539294296,而"python"(一个按位不同的字符串)的 hash 值为 1142331976。然后,hash 代码用于计算内部数组中将存储该值的位置。假设您存储的键都具有不同的 hash 值,这意味着字典需要恒定的时间 -- O(1),用 Big-O 表示法 -- 来检索一个键。
End.
来源:Python官方文档、中国统计网

零基础学 Python,来这里

只需7天时间,跨进Python编程大门,已有3800+加入

【基础】0基础入门python,24小时有人快速解答问题;
【提高】40多个项目实战,老手可以从真实场景中学习python;
【直播】不定期直播项目案例讲解,手把手教你如何分析项目;
【分享】优质python学习资料分享,让你在最短时间获得有价值的学习资源;圈友优质资料或学习分享,会不时给予赞赏支持,希望每个优质圈友既能赚回加入费用,也能快速成长,并享受分享与帮助他人的乐趣。
【人脉】收获一群志同道合的朋友,并且都是python从业者
【价格】本着布道思想,只需 69元 加入一个能保证学习效果的良心圈子。

【赠予】后续圈主将开发python,0基础入门在线课程,免费送给圈友们,供巩固和系统化复习

(三重福利)最近入圈送大礼包:

1、2.7G、308份最新数据分析报告
2、40G 人工智能算法  视频课
3、Python爬虫课,共14课


更多精彩

在公众号后台对话框输入以下关键词

查看更多优质内容!

PM2.5 | 世界杯 | 惊喜 | 附书代码

觉得不错,请把这篇文章分享给你的朋友

转载 / 投稿请联系:data_circle_yoni

● 总结 Python 的4张超大思维导图,一定不要错过哦

● 知乎13万赞!为何很多名校毕业生,都输在了人生后半程

● 【连载】小白轻松学Python ---- 到底如何入门  Python?

● 怎么才能自学成 Python 大牛?这有些建议

● Python打牢基础,从22个语法开始!

● 手把手 | 爬取京东评论,且修改网址直接可复用哦(送代码)

● 为何“Python 之父” 力荐的小蓝书火了?

● Python实战 | 只需 ”三步“ 爬取二手iphone手机信息(转发送源码)

● 做数据分析不得不看的书有哪些?

● Python实战 | 手把手教你爬取豆瓣电影 Top 250(附全部代码)

好看请点这里~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值