假期让你秒变Ph高手

如题所述

第1个回答  2023-06-14

搞懂这些问题让你秒变Python高手快来学习吧

搞懂这些问题, 让你秒变Pytho高手

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

Guido van Rossum认为使用缩进进行分组非常优雅, 并且大大

提高了普通Python程序的清晰度。大多数人在一段时间后就学

会并喜欢上这个功能。

由于没有开始/结束括号,因此解析器感知的分组与人类读者之

间不会存在分歧。偶尔C程序员会遇到像这样的代码片段:

如果条件为真,则只执行x++语句,但缩进会使你认为情况并

非如此。即使是经验丰富的C程序员有时会长时间盯着它,想

知道为什么即使x>y,y也在减少。

因为没有开始/结束括号, 所以Python不太容易发生编码式冲

突。在C中,括号可以放到许多不同的位置。如果您习惯于阅

读和编写使用一种风格的代码,那么在阅读(或被要求编写)

另一种风格时,您至少会感到有些不安。

许多编码风格将开始/结束括号单独放在一行上。这使得程序相

当长,浪费了宝贵的屏幕空间,使得更难以对程序进行全面的

搞懂这些问题, 让你秒变Pytho高手

了解。理想情况下,函数应该适合一个屏幕(例如,20--30行

) 。20行Python可以完成比20行C更多的工作。这不仅仅是

由于缺少开始/结束括号--缺少声明和高级数据类型也是其中的

原因--但缩进基于语法肯定有帮助。

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

请看下一个问题。

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

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

并且认为这是Python中的一个bug。其实不是这样。这与

Python关系不大, 而与底层平台如何处理浮点数字关系更大。

CPython中的float类型使用C语言的double类型进行存储。

float对象的值是以固定的精度(通常为53位) 存储的二进制

浮点数, 由于Python使用C操作, 而后者依赖于处理器中的

硬件实现来执行浮点运算。这意味着就浮点运算而言, Python

的行为类似于许多流行的语言, 包括C和Java。

许多可以轻松地用十进制表示的数字不能用二进制浮点表示。

例如,在输入以下语句后:

搞懂这些问题, 让你秒变Pytho高手

>>>x=1.2

为x存储的值是与十进制的值1.2(非常接近)的近似值,但不完

全等于它。在典型的机器上,实际存储的值是:

1.8811601198116911901160119911891190118011001180110011

(binary)

它对应于十进制数值:

1.1999999999999999555910790149937383830547332763671875

(decimal)

典型的53位精度为Python浮点数提供了15-16位小数的精度

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

有几个优点。

一个是性能:知道字符串是不可变的,意味着我们可以在创建

时为它分配空间,并且存储需求是固定不变的。这也是元组和

列表之间区别的原因之一。

另一个优点是, Python中的字符串被视为与数字一样“基本”

。任何动作都不会将值8更改为其他值, 在Python中, 任何动

作都不会将字符串"8"更改为其他值。

5.为什么必须在方法定义和调用中显式使用“self”?

这个想法借鉴了Modula-3语言。出于多种原因它被证明是非常

有用的。

搞懂这些问题,让你秒变Pytho高手

首先,更明显的显示出,使用的是方法或实例属性而不是局部

变量。阅读self.x或self.meth() 可以清楚地表明, 即使您不知

道类的定义,也会使用实例变量或方法。在C++中,可以通过

缺少局部变量声明来判断(假设全局变量很少见或容易识别)

--但是在Python中没有局部变量声明, 所以必须查找类定义

才能确定。一些C++和Java编码标准要求实例属性具有m_前

缀,因此这种显式性在这些语言中仍然有用。

其次,这意味着如果要显式引用或从特定类调用该方法,不需

要特殊语法。在C++中,如果你想使用在派生类中重写基类中

的方法, 你必须使用::运算符--在Python中你可以编写

baseclass.methodname(self, ) 。这对于in it() 方法非常有用,

特别是在派生类方法想要扩展同名的基类方法,而必须以某种

方式调用基类方法时。

最后, 它解决了变量赋值的语法问题:为了Python中的局部变

量(根据定义!)在函数体中赋值的那些变量(并且没有明确

声明为全局)赋值,就必须以某种方式告诉解释器一个赋值是

为了分配一个实例变量而不是一个局部变量,它最好是通过语

法实现的(出于效率原因)。C++通过声明来做到这一点,但

是Python没有声明, 仅仅为了这个目的而引入它们会很可惜。

使用显式的self.var很好地解决了这个问题。类似地, 对于使用

搞懂这些问题, 让你秒变Pytho高手

实例变量, 必须编写self var意味着对方法内部的非限定名称的

引用不必搜索实例的目录。换句话说,局部变量和实例变量存

在于两个不同的命名空间中, 您需要告诉Python使用哪个命名

空间。

6.为什么不能在表达式中赋值?

不允许在Python表达式中赋值的原因是这些其他语言中常见的

、很难发现的错误,是由这个结构引起的:

错误是一个简单的错字:x=0,将0赋给变量x,而比较x==

0肯定是可以预期的。

已经有许多替代方案提案。大多数是为了少打一些字的黑客方

案,但使用任意或隐含的语法或关键词,并不符合语言变更提

案的简单标准:它应该直观地向尚未被介绍到这一概念的人类

读者提供正确的含义。

最好的方法是使用迭代器, 这样能通过for语句来循环遍历对象

。例如file objects支持迭代器协议, 因此可以简单地写成:

搞懂这些问题, 让你秒变Pytho高手

7为什么Python对某些功能(例如list.index() ) 使用

方法来实现, 而其他功能(例如len(List) ) 使用函数

实现?

(a)对于某些操作,前缀表示法比后缀更容易阅读--前缀(和中

缀!)运算在数学中有着悠久的传统,就像在视觉上帮助数学

家思考问题的记法。比较一下我们将x*(a+b)这样的公式改写为

x_a+x_b的容易程度,以及使用原始00符号做相同事情的笨

拙程度。”

(b) 当读到写有len(X) 的代码时, 就知道它要求的是某件东西的

长度。这告诉我们两件事:结果是一个整数,参数是某种容器

。相反, 当阅读x.len() 时, 必须已经知道x是某种实现接口的

容器, 或者是从具有标准len() 的类继承的容器。当没有实现映

射的类有get() 或key() 方法, 或者不是文件的类有write() 方法

时,我们偶尔会感到困惑。

8.为什么join) 是一个字符串方法而不是列表或元组方

法?

join() 是字符串方法, 因为在使用该方法时, 您告诉分隔符字符

串去迭代一个字符串序列,并在相邻元素之间插入自身。此方

法的参数可以是任何遵循序列规则的对象,包括您自己定义的

任何新的类。对于字节和字节数组对象也有类似的方法。

搞懂这些问题, 让你秒变Pytho高手

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

Python的lambda表达式不能包含语句, 因为Python的语法

框架不能处理嵌套在表达式内部的语句。然而, 在Python中,

这并不是一个严重的问题。与其他语言中添加功能的lambda

表单不同, Python的lambdas只是一种速记符号, 如果您懒

得定义函数的话。

函数已经是Python中的第一类对象, 可以在本地范围内声明。

因此, 使用lambda而不是本地定义的函数的唯一优点是你不

需要为函数创建一个名称--这只是一个分配了函数对象(与

lambda表达式生成的对象类型完全相同) 的局部变量!

10.难道不能在解释器中模拟线程,而非得依赖特定于

操作系统的线程实现吗?

答案1:不幸的是, 解释器为每个Python堆栈帧推送至少一个

C堆栈帧。此外, 扩展可以随时回调Python。因此, 一个完整

的线程实现需要对C的线程支持。

答案2:幸运的是, Stackless Python有一个完全重新设计的

解释器循环,可以避免C堆栈。