爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      Python 设计和历史的 27 个问题

      首页 知识中心 软件开发 文章详情页

      Python 设计和历史的 27 个问题

      2025-02-26 07:20:01 阅读次数:12

      Python,使用,元组,列表,字典,字符串,方法

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

      Guido van Rossum 认为使用缩进进行分组非常优雅,并且大大提高了普通Python程序的清晰度。大多数人在一段时间后就学会并喜欢上这个功能。

      由于没有开始/结束括号,因此解析器感知的分组与人类读者之间不会存在分歧。偶尔C程序员会遇到像这样的代码片段:

      if (x <= y)
              x++;
              y--;
      z++;
      
      

      如果条件为真,则只执行 x++ 语句,但缩进会使你认为情况并非如此。即使是经验丰富的C程序员有时会长时间盯着它,想知道为什么即使 x > y , y 也在减少。

      因为没有开始/结束括号,所以Python不太容易发生编码式冲突。在C中,括号可以放到许多不同的位置。如果您习惯于阅读和编写使用一种风格的代码,那么在阅读(或被要求编写)另一种风格时,您至少会感到有些不安。

      许多编码风格将开始/结束括号单独放在一行上。这使得程序相当长,浪费了宝贵的屏幕空间,使得更难以对程序进行全面的了解。理想情况下,函数应该适合一个屏幕(例如,20--30行)。 20行Python可以完成比20行C更多的工作。这不仅仅是由于缺少开始/结束括号 -- 缺少声明和高级数据类型也是其中的原因 -- 但缩进基于语法肯定有帮助。

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

      请看下一个问题。

      为什么浮点计算不准确?

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

      >>> 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 教程中的 浮点算术 一章。

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

      有几个优点。

      一个是性能:知道字符串是不可变的,意味着我们可以在创建时为它分配空间,并且存储需求是固定不变的。这也是元组和列表之间区别的原因之一。

      另一个优点是,Python 中的字符串被视为与数字一样“基本”。 任何动作都不会将值 8 更改为其他值,在 Python 中,任何动作都不会将字符串 "8" 更改为其他值。

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

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

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

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

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

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

      许多习惯于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...
      
      

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

      正如Guido所说:

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

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

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

      为什么 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() 是字符串方法,因为在使用该方法时,您告诉分隔符字符串去迭代一个字符串序列,并在相邻元素之间插入自身。此方法的参数可以是任何遵循序列规则的对象,包括您自己定义的任何新的类。对于字节和字节数组对象也有类似的方法。

      异常有多快?

      如果没有引发异常,则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()足够便宜,因为在所有情况下都会对其进行评估。

      为什么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_ 。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。

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

      答案1: 不幸的是,解释器为每个Python堆栈帧推送至少一个C堆栈帧。此外,扩展可以随时回调Python。因此,一个完整的线程实现需要对C的线程支持。

      答案2: 幸运的是, Stackless Python 有一个完全重新设计的解释器循环,可以避免C堆栈。

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

      Python的 lambda表达式不能包含语句,因为Python的语法框架不能处理嵌套在表达式内部的语句。然而,在Python中,这并不是一个严重的问题。与其他语言中添加功能的lambda表单不同,Python的 lambdas只是一种速记符号,如果您懒得定义函数的话。

      函数已经是Python中的第一类对象,可以在本地范围内声明。 因此,使用lambda而不是本地定义的函数的唯一优点是你不需要为函数创建一个名称 -- 这只是一个分配了函数对象(与lambda表达式生成的对象类型完全相同)的局部变量!

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

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

      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)
      
      

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

      首先,这不是C标准特性,因此不能移植。(是的,我们知道Boehm GC库。它包含了 大多数 常见平台(但不是所有平台)的汇编代码,尽管它基本上是透明的,但也不是完全透明的; 要让Python使用它,需要使用补丁。)

      当Python嵌入到其他应用程序中时,传统的GC也成为一个问题。在独立的Python中,可以用GC库提供的版本替换标准的malloc()和free(),嵌入Python的应用程序可能希望用 它自己 替代malloc()和free(),而可能不需要Python的。现在,CPython可以正确地实现malloc()和free()。

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

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

      如果要强制 Python 在释放时删除某些内容,请使用 atexit 模块运行一个函数,强制删除这些内容。

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

      虽然列表和元组在许多方面是相似的,但它们的使用方式通常是完全不同的。可以认为元组类似于Pascal记录或C结构;它们是相关数据的小集合,可以是不同类型的数据,可以作为一个组进行操作。例如,笛卡尔坐标适当地表示为两个或三个数字的元组。

      另一方面,列表更像其他语言中的数组。它们倾向于持有不同数量的对象,所有对象都具有相同的类型,并且逐个操作。例如, os.listdir('.') 返回表示当前目录中的文件的字符串列表。如果向目录中添加了一两个文件,对此输出进行操作的函数通常不会中断。

      元组是不可变的,这意味着一旦创建了元组,就不能用新值替换它的任何元素。列表是可变的,这意味着您始终可以更改列表的元素。只有不变元素可以用作字典的key,因此只能将元组和非列表用作key。

      列表是如何在CPython中实现的?

      CPython的列表实际上是可变长度的数组,而不是lisp风格的链表。该实现使用对其他对象的引用的连续数组,并在列表头结构中保留指向该数组和数组长度的指针。

      这使得索引列表 a[i] 的操作成本与列表的大小或索引的值无关。

      当添加或插入项时,将调整引用数组的大小。并采用了一些巧妙的方法来提高重复添加项的性能; 当数组必须增长时,会分配一些额外的空间,以便在接下来的几次中不需要实际调整大小。

      字典是如何在CPython中实现的?

      CPython的字典实现为可调整大小的哈希表。与B-树相比,这在大多数情况下为查找(目前最常见的操作)提供了更好的性能,并且实现更简单。

      字典的工作方式是使用 hash() 内置函数计算字典中存储的每个键的hash代码。hash代码根据键和每个进程的种子而变化很大;例如,"Python" 的hash值为-539294296,而"python"(一个按位不同的字符串)的hash值为1142331976。然后,hash代码用于计算内部数组中将存储该值的位置。假设您存储的键都具有不同的hash值,这意味着字典需要恒定的时间 -- O(1),用Big-O表示法 -- 来检索一个键。

      为什么字典key必须是不可变的?

      字典的哈希表实现使用从键值计算的哈希值来查找键。如果键是可变对象,则其值可能会发生变化,因此其哈希值也会发生变化。但是,由于无论谁更改键对象都无法判断它是否被用作字典键值,因此无法在字典中修改条目。然后,当你尝试在字典中查找相同的对象时,将无法找到它,因为其哈希值不同。如果你尝试查找旧值,也不会找到它,因为在该哈希表中找到的对象的值会有所不同。

      如果你想要一个用列表索引的字典,只需先将列表转换为元组;用函数 tuple(L) 创建一个元组,其条目与列表 L相同。 元组是不可变的,因此可以用作字典键。

      已经提出的一些不可接受的解决方案:

      • 哈希按其地址(对象ID)列出。这不起作用,因为如果你构造一个具有相同值的新列表,它将无法找到;例如:

        mydict = {[1, 2]: '12'}
        print(mydict[[1, 2]])
        
        

        会引发一个 KeyError 异常,因为第二行中使用的 [1, 2] 的 id 与第一行中的 id 不同。换句话说,应该使用 == 来比较字典键,而不是使用 is 。

      • 使用列表作为键时进行复制。这没有用的,因为作为可变对象的列表可以包含对自身的引用,然后复制代码将进入无限循环。

      • 允许列表作为键,但告诉用户不要修改它们。当你意外忘记或修改列表时,这将产生程序中的一类难以跟踪的错误。它还使一个重要的字典不变量无效: d.keys() 中的每个值都可用作字典的键。

      • 将列表用作字典键后,应标记为其只读。问题是,它不仅仅是可以改变其值的顶级对象;你可以使用包含列表作为键的元组。将任何内容作为键关联到字典中都需要将从那里可到达的所有对象标记为只读 —— 并且自引用对象可能会导致无限循环。

      如果需要,可以使用以下方法来解决这个问题,但使用它需要你自担风险:你可以将一个可变结构包装在一个类实例中,该实例同时具有 __eq__() 和 __hash__() 方法。然后,你必须确保驻留在字典(或其他基于 hash 的结构)中的所有此类包装器对象的哈希值在对象位于字典(或其他结构)中时保持固定。:

      class ListWrapper:
          def __init__(self, the_list):
              self.the_list = the_list
      
          def __eq__(self, other):
              return self.the_list == other.the_list
      
          def __hash__(self):
              l = self.the_list
              result = 98767 - len(l)*555
              for i, el in enumerate(l):
                  try:
                      result = result + (hash(el) % 9999999) * 1001 + i
                  except Exception:
                      result = (result % 7777777) + i * 333
              return result
      
      

      注意,哈希计算由于列表的某些成员可能不可用以及算术溢出的可能性而变得复杂。

      此外,必须始终如此,如果 o1 == o2 (即 o1.__eq__(o2) is True )则 hash(o1) == hash(o2)``(即``o1.__hash__() == o2.__hash__() ),无论对象是否在字典中。 如果你不能满足这些限制,字典和其他基于 hash 的结构将会出错。

      对于 ListWrapper ,只要包装器对象在字典中,包装列表就不能更改以避免异常。除非你准备好认真考虑需求以及不正确地满足这些需求的后果,否则不要这样做。请留意。

      为什么 list.sort() 没有返回排序列表?

      在性能很重要的情况下,仅仅为了排序而复制一份列表将是一种浪费。因此, list.sort() 对列表进行了适当的排序。为了提醒您这一事实,它不会返回已排序的列表。这样,当您需要排序的副本,但也需要保留未排序的版本时,就不会意外地覆盖列表。

      如果要返回新列表,请使用内置 sorted() 函数。此函数从提供的可迭代列表中创建新列表,对其进行排序并返回。例如,下面是如何迭代遍历字典并按keys排序:

      for key in sorted(mydict):
          ...  # do whatever with mydict[key]...
      
      

      如何在Python中指定和实施接口规范?

      由C++和Java等语言提供的模块接口规范描述了模块的方法和函数的原型。许多人认为接口规范的编译时强制执行有助于构建大型程序。

      Python 2.6添加了一个 abc 模块,允许定义抽象基类 (ABCs)。然后可以使用 isinstance() 和 issubclass() 来检查实例或类是否实现了特定的ABC。 collections.abc 模块定义了一组有用的ABCs 例如 Iterable , Container , 和 MutableMapping

      对于Python,通过对组件进行适当的测试规程,可以获得接口规范的许多好处。还有一个工具PyChecker,可用于查找由于子类化引起的问题。

      一个好的模块测试套件既可以提供回归测试,也可以作为模块接口规范和一组示例。许多Python模块可以作为脚本运行,以提供简单的“自我测试”。即使是使用复杂外部接口的模块,也常常可以使用外部接口的简单“桩代码(stub)”模拟进行隔离测试。可以使用 doctest 和 unittest 模块或第三方测试框架来构造详尽的测试套件,以运行模块中的每一行代码。

      适当的测试规程可以帮助在Python中构建大型的、复杂的应用程序以及接口规范。事实上,它可能会更好,因为接口规范不能测试程序的某些属性。例如, append() 方法将向一些内部列表的末尾添加新元素;接口规范不能测试您的 append() 实现是否能够正确执行此操作,但是在测试套件中检查这个属性是很简单的。

      编写测试套件非常有用,您可能希望设计代码时着眼于使其易于测试。一种日益流行的技术是面向测试的开发,它要求在编写任何实际代码之前,首先编写测试套件的各个部分。当然,Python允许您草率行事,根本不编写测试用例。

      为什么没有goto?

      可以使用异常捕获来提供 “goto结构” ,甚至可以跨函数调用工作的 。许多人认为异常捕获可以方便地模拟C,Fortran和其他语言的 "go" 或 "goto" 结构的所有合理用法。例如:

      class label(Exception): pass  # declare a label
      
      try:
          ...
          if condition: raise label()  # goto label
          ...
      except label:  # where to goto
          pass
      ...
      
      

      但是不允许你跳到循环的中间,这通常被认为是滥用goto。谨慎使用。

      为什么原始字符串(r-strings)不能以反斜杠结尾?

      更准确地说,它们不能以奇数个反斜杠结束:结尾处的不成对反斜杠会转义结束引号字符,留下未结束的字符串。

      原始字符串的设计是为了方便想要执行自己的反斜杠转义处理的处理器(主要是正则表达式引擎)创建输入。此类处理器将不匹配的尾随反斜杠视为错误,因此原始字符串不允许这样做。反过来,允许通过使用引号字符转义反斜杠转义字符串。当r-string用于它们的预期目的时,这些规则工作的很好。

      如果您正在尝试构建Windows路径名,请注意所有Windows系统调用都使用正斜杠:

      f = open("/mydir/file.txt")  # works fine!
      
      

      如果您正在尝试为DOS命令构建路径名,请尝试以下示例

      dir = r"\this\is\my\dos\dir" "\\"
      dir = r"\this\is\my\dos\dir\ "[:-1]
      dir = "\\this\\is\\my\\dos\\dir\\"
      
      

      为什么Python没有属性赋值的“with”语句?

      Python有一个 'with' 语句,它封装了块的执行,在块的入口和出口调用代码。有些语言的结构是这样的:

      with obj:
          a = 1               # equivalent to obj.a = 1
          total = total + 1   # obj.total = obj.total + 1
      
      

      在Python中,这样的结构是不明确的。

      其他语言,如ObjectPascal、Delphi和C++ 使用静态类型,因此可以毫不含糊地知道分配给什么成员。这是静态类型的要点 -- 编译器 总是 在编译时知道每个变量的作用域。

      Python使用动态类型。事先不可能知道在运行时引用哪个属性。可以动态地在对象中添加或删除成员属性。这使得无法通过简单的阅读就知道引用的是什么属性:局部属性、全局属性还是成员属性?

      例如,采用以下不完整的代码段:

      def foo(a):
          with a:
              print(x)
      
      

      该代码段假设 "a" 必须有一个名为 "x" 的成员属性。然而,Python中并没有告诉解释器这一点。假设 "a" 是整数,会发生什么?如果有一个名为 "x" 的全局变量,它是否会在with块中使用?如您所见,Python的动态特性使得这样的选择更加困难。

      然而,Python 可以通过赋值轻松实现 "with" 和类似语言特性(减少代码量)的主要好处。代替:

      function(args).mydict[index][index].a = 21
      function(args).mydict[index][index].b = 42
      function(args).mydict[index][index].c = 63
      
      

      写成这样:

      ref = function(args).mydict[index][index]
      ref.a = 21
      ref.b = 42
      ref.c = 63
      
      

      这也具有提高执行速度的副作用,因为Python在运行时解析名称绑定,而第二个版本只需要执行一次解析。

      为什么 if/while/def/class语句需要冒号?

      冒号主要用于增强可读性(ABC语言实验的结果之一)。考虑一下这个:

      if a == b
          print(a)
      
      

      与

      if a == b:
          print(a)
      
      

      注意第二种方法稍微容易一些。请进一步注意,在这个FAQ解答的示例中,冒号是如何设置的;这是英语中的标准用法。

      另一个次要原因是冒号使带有语法突出显示的编辑器更容易工作;他们可以寻找冒号来决定何时需要增加缩进,而不必对程序文本进行更精细的解析。

      为什么Python在列表和元组的末尾允许使用逗号?

      Python 允许您在列表,元组和字典的末尾添加一个尾随逗号:

      [1, 2, 3,]
      ('a', 'b', 'c',)
      d = {
          "A": [1, 5],
          "B": [6, 7],  # last trailing comma is optional but good style
      }
      
      

      有几个理由允许这样做。

      如果列表,元组或字典的字面值分布在多行中,则更容易添加更多元素,因为不必记住在上一行中添加逗号。这些行也可以重新排序,而不会产生语法错误。

      不小心省略逗号会导致难以诊断的错误。例如:

      x = [
        "fee",
        "fie"
        "foo",
        "fum"
      ]
      
      

      这个列表看起来有四个元素,但实际上包含三个 : "fee", "fiefoo" 和 "fum" 。总是加上逗号可以避免这个错误的来源。

      允许尾随逗号也可以使编程代码更容易生成。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://www.cnblogs.com/pythonista/p/11617152.html,作者:豌豆花下猫,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:JavaWeb前端常用的代码复用总结

      下一篇:Python 为什么推荐蛇形命名法?

      相关文章

      2025-05-19 09:04:38

      使用列表实现名片管理系统的增删改查。

      使用列表实现名片管理系统的增删改查。

      2025-05-19 09:04:38
      code , 列表 , 改查
      2025-05-19 09:04:22

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      2025-05-19 09:04:22
      使用 , 函数 , 初始化 , 定义 , 对象
      2025-05-19 09:04:14

      C语言字符函数和字符串函数--(超全超详细)

      C语言字符函数和字符串函数--(超全超详细)

      2025-05-19 09:04:14
      函数 , 字符 , 字符串
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      2025-05-14 10:33:25

      30天拿下Rust之网络编程

      在现代软件开发中,网络编程无处不在。无论是构建高性能的服务器、实时通信应用,还是实现复杂的分布式系统,对网络编程技术的掌握都至关重要。Rust语言以其卓越的安全性、高性能和优秀的并发模型,为网络编程提供了坚实的基础。

      2025-05-14 10:33:25
      Rust , TCP , 使用 , 客户端 , 异步 , 编程
      2025-05-14 10:33:16

      30天拿下Rust之切片

      在Rust中,切片是一种非常重要的引用类型。它允许你安全地引用一段连续内存中的数据,而不需要拥有这些数据的所有权。切片不包含分配的内存空间,它仅仅是一个指向数据开始位置和长度的数据结构。

      2025-05-14 10:33:16
      amp , end , 切片 , 字符串 , 引用 , 索引 , 迭代
      2025-05-14 10:33:16

      30天拿下Python之使用Json

      Json的英文全称为JavaScript Object Notation,中文为JavaScript对象表示法,是一种存储和交换文本信息的语法,类似XML。Json作为轻量级的文本数据交换格式,比XML更小、更快,更易解析,也更易于阅读和编写。

      2025-05-14 10:33:16
      json , Json , Python , 字符串 , 对象 , 序列化 , 转换
      2025-05-14 10:33:16

      30天拿下Rust之字符串

      在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:&str和String。其中,&str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实体。

      2025-05-14 10:33:16
      amp , Rust , str , String , 使用 , 字符串 , 方法
      2025-05-14 10:33:16

      30天拿下Rust之向量

      在Rust语言中,向量(Vector)是一种动态数组类型,可以存储相同类型的元素,并且可以在运行时改变大小。向量是Rust标准库中的一部分,位于std::vec模块中。

      2025-05-14 10:33:16
      Rust , 使用 , 元素 , 向量 , 方法 , 索引 , 迭代
      2025-05-14 10:33:16

      30天拿下Python之文件操作

      Python是一种高级编程语言,它提供了许多内置函数和模块来处理文件操作,主要包括:打开文件、读取文件、写入文件、关闭文件、获取目录列表等。

      2025-05-14 10:33:16
      Python , 使用 , 函数 , 文件 , 权限 , 目录
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5242008

      查看更多

      最新文章

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      2025-05-19 09:04:22

      C语言字符函数和字符串函数--(超全超详细)

      2025-05-19 09:04:14

      30天拿下Python之使用Json

      2025-05-14 10:33:16

      30天拿下Rust之向量

      2025-05-14 10:33:16

      30天拿下Python之文件操作

      2025-05-14 10:33:16

      30天拿下Python之迭代器和生成器

      2025-05-14 10:07:38

      查看更多

      热门文章

      Python标准输入输出

      2023-04-18 14:15:05

      Python高级变量类型

      2024-09-24 06:30:08

      mysql列存储引擎-字符串属性列-列压缩测试

      2023-04-23 09:34:23

      Python:matplotlib分组Bar柱状图

      2024-09-25 10:15:01

      刷题——Python篇(2)类型转换

      2023-02-13 07:58:38

      Python Pandas将多个dataframe写入Excel文件

      2023-04-21 03:11:35

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      巧妙驾驭JavaScript字符串:常用方法大揭秘

      Java创建对象有几种方式

      列表 选择排序算法

      【多线程】c++11多线程编程(三)——竞争条件与互斥锁

      【Java基础语法】抽象类和接口

      还在为Python变量中遇到的BUG而发愁吗?,变量相关的问题和解决办法看这篇文章就够了!

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号