Python 27问,助更好的掌握Python!_python visit

因为没有开始/结束括号,所以 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. 为什么必须在方法定义和调用中显式使用“self”?

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

首先,更明显的显示出,使用的是方法或实例属性而不是局部变量。阅读 self.x 或 self.meth() 可以清楚地表明,即使您不知道类的定义,也会使用实例变量或方法。在 C++ 中,可以通过缺少局部变量声明来判断(假设全局变量很少见或容易识别) —— 但是在 Python 中没有局部变量声明,所以必须查找类定义才能确定。一些 C++ 和 Java 编码标准要求实例属性具有 m_ 前缀,因此这种显式性在这些语言中仍然有用。

其次,这意味着如果要显式引用或从特定类调用该方法,不需要特殊语法。在 C++ 中,如果你想使用在派生类中重写基类中的方法,你必须使用 :: 运算符 – 在 Python 中你可以编写 baseclass.methodname(self, )。这对于 init() 方法非常有用,特别是在派生类方法想要扩展同名的基类方法,而必须以某种方式调用基类方法时。

最后,它解决了变量赋值的语法问题:为了 Python 中的局部变量(根据定义!)在函数体中赋值的那些变量(并且没有明确声明为全局)赋值,就必须以某种方式告诉解释器一个赋值是为了分配一个实例变量而不是一个局部变量,它最好是通过语法实现的(出于效率原因)。C++ 通过声明来做到这一点,但是 Python 没有声明,仅仅为了这个目的而引入它们会很可惜。使用显式的 self.var 很好地解决了这个问题。类似地,对于使用实例变量,必须编写 self.var 意味着对方法内部的非限定名称的引用不必搜索实例的目录。换句话说,局部变量和实例变量存在于两个不同的命名空间中,您需要告诉 Python 使用哪个命名空间。

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

许多习惯于 C 或 Perl 的人抱怨,他们想要使用 C 的这个特性:

while (line = readline(f)) {
    // do something with line
}
但在 Python 中被强制写成这样:
while True:
    line = f.readline()
    if not line:
        break
    ...  # do something with line

不允许在 Python 表达式中赋值的原因是这些其他语言中常见的、很难发现的错误,是由这个结构引起的:

if (x = 0) {
    // error handling
}
else {
    // code that only works for nonzero x
}

错误是一个简单的错字:x = 0 ,将 0 赋给变量 x ,而比较 x == 0 肯定是可以预期的。
已经有许多替代方案提案。大多数是为了少打一些字的黑客方案,但使用任意或隐含的语法或关键词,并不

符合语言变更提案的简单标准:它应该直观地向尚未被介绍到这一概念的人类读者提供正确的含义。
一个有趣的现象是,大多数有经验的 Python 程序员都认识到 while True 的习惯用法,也不太在意是否能在

表达式构造中赋值; 只有新人表达了强烈的愿望希望将其添加到语言中。

有一种替代的拼写方式看起来很有吸引力,但通常不如"while True"解决方案可靠:

line = f.readline()
while line:
    ...  # do something with line...
    line = f.readline()

问题在于,如果你改变主意(例如你想把它改成 sys.stdin.readline() ),如何知道下一行。你必须记住改变程序中的两个地方 – 第二次出现隐藏在循环的底部。
最好的方法是使用迭代器,这样能通过 for 语句来循环遍历对象。例如 file objects 支持迭代器协议,因此可以简单地写成:

for line in f:
    ...  # do something with line...

07 为什么 Python 对某些功能(例如 list.index())使用方法来实现,而其他功能(例如 len(List))使用函数实现?

正如 Guido 所说:
(a) 对于某些操作,前缀表示法比后缀更容易阅读 – 前缀(和中缀!)运算在数学中有着悠久的传统,就像在视觉上帮助数学家思考问题的记法。比较一下我们将 x*(a+b) 这样的公式改写为 xa+xb 的容易程度,以及使用原始 OO 符号做相同事情的笨拙程度。”

(b) 当读到写有 len(X)的代码时,就知道它要求的是某件东西的长度。这告诉我们两件事:结果是一个整数,参数是某种容器。相反,当阅读 x.len()时,必须已经知道 x 是某种实现接口的容器,或者是从具有标准 len()的类继承的容器。当没有实现映射的类有 get()或 key()方法,或者不是文件的类有 write()方法时,我们偶尔会感到困惑。

—https://mail.python.org/pipermail/python-3000/2006-November/004643.html”

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

从 Python 1.6 开始,字符串变得更像其他标准类型,当添加方法时,这些方法提供的功能与始终使用 String 模块的函数时提供的功能相同。这些新方法中的大多数已被广泛接受,但似乎让一些程序员感到不舒服的一种方法是:
", ".join([‘1’, ‘2’, ‘4’, ‘8’, ‘16’])

结果如下:
“1, 2, 4, 8, 16”

反对这种用法有两个常见的论点。
第一条是这样的:“使用字符串文本(String Constant)的方法看起来真的很难看”,答案是也许吧,但是字符串文本只是一个固定值。如果在绑定到字符串的名称上允许使用这些方法,则没有逻辑上的理由使其在文字上不可用。

第二个异议通常是这样的:“我实际上是在告诉序列使用字符串常量将其成员连接在一起”。遗憾的是并非如此。出于某种原因,把 split() 作为一个字符串方法似乎要容易得多,因为在这种情况下,很容易看到:

"1, 2, 4, 8, 16".split(", ")

是对字符串文本的指令,用于返回由给定分隔符分隔的子字符串(或在默认情况下,返回任意空格)。
join() 是字符串方法,因为在使用该方法时,您告诉分隔符字符串去迭代一个字符串序列,并在相邻元素之间插入自身。此方法的参数可以是任何遵循序列规则的对象,包括您自己定义的任何新的类。对于字节和字节数组对象也有类似的方法。

09. 异常有多快?

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

try:
    value = mydict[key]
except KeyError:
    mydict[key] = getvalue(key)


现在能在网上找到很多很多的学习资源,有免费的也有收费的,当我拿到1套比较全的学习资源之前,我并没着急去看第1节,我而是去审视这套资源是否值得学习,有时候也会去问一些学长的意见,如果可以之后,我会对这套学习资源做1个学习计划,我的学习计划主要包括规划图和学习进度表。



分享给大家这份我薅到的免费视频资料,质量还不错,大家可以跟着学习

![](https://img-blog.csdnimg.cn/img_convert/21b2604bd33c4b6713f686ddd3fe5aff.png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值