你现在的位置:首页 > 深入 Python > 技巧和窍门 | << >> | ||||
深入 Python从 Python 新手到专家 |
![]() |
|
在 Windows 上的 ActivePython IDE 中,你可以通过选择 -> (Ctrl-R) 来运行你正在编辑的 Python 程序。输出显示在交互式窗口中。 |
![]() |
|
在 Mac OS 上的 Python IDE 中,你可以使用 -> (Cmd-R) 运行 Python 程序,但你需要先设置一个重要的选项。在 IDE 中打开 .py 文件,点击窗口右上角的黑色三角形弹出选项菜单,并确保选中了 选项。这是一个针对每个文件的设置,但你只需要为每个文件设置一次。 |
![]() |
|
在 UNIX 兼容系统(包括 Mac OS X)上,你可以从命令行运行 Python 程序:python odbchelper.py |
![]() |
|
在 Visual Basic 中,函数(返回值)以 function 开头,子程序(不返回值)以 sub 开头。在 Python 中没有子程序。一切都是函数,所有函数都返回一个值(即使是 None),并且所有函数都以 def 开头。 |
![]() |
|
在 Java、C++ 和其他静态类型语言中,你必须指定函数返回值和每个函数参数的数据类型。在 Python 中,你永远不会显式指定任何东西的数据类型。根据你赋予的值,Python 会在内部跟踪数据类型。 |
![]() |
|
三引号也是定义包含单引号和双引号的字符串的简单方法,就像 Perl 中的 qq/.../。 |
![]() |
|
许多 Python IDE 使用 docstring 提供上下文相关的文档,因此当你键入函数名称时,其 docstring 将显示为工具提示。这可能非常有帮助,但这取决于你编写的 docstring 的质量。 |
![]() |
|
Python 中的 import 就像 Perl 中的 require。当你 import 一个 Python 模块后,你可以使用 module.function 访问其函数;当你 require 一个 Perl 模块后,你可以使用 module::function 访问其函数。 |
![]() |
|
Python 使用回车符分隔语句,并使用冒号和缩进分隔代码块。C++ 和 Java 使用分号分隔语句,并使用花括号分隔代码块。 |
![]() |
|
与 C 类似,Python 使用 == 进行比较,使用 = 进行赋值。与 C 不同,Python 不支持内联赋值,因此你不会意外地将你认为正在比较的值赋给变量。 |
![]() |
|
在 MacPython 上,要使 if __name__ 技巧生效,还需要执行一个额外的步骤。点击窗口右上角的黑色三角形弹出模块的选项菜单,并确保选中了 。 |
![]() |
|
Python 中的字典就像 Perl 中的哈希表。在 Perl 中,存储哈希表的变量始终以 % 字符开头。在 Python 中,变量可以任意命名,Python 会在内部跟踪数据类型。 |
![]() |
|
Python 中的字典就像 Java 中的 Hashtable 类的一个实例。 |
![]() |
|
Python 中的字典就像 Visual Basic 中的 Scripting.Dictionary 对象的一个实例。 |
![]() |
|
字典中的元素没有顺序概念。说元素“无序”是不正确的;它们只是无序的。这是一个重要的区别,当你想要以特定的、可重复的顺序(例如按键的字母顺序)访问字典的元素时,这会让你感到烦恼。有一些方法可以做到这一点,但它们不是字典的内置功能。 |
![]() |
|
Python 中的列表就像 Perl 中的数组。在 Perl 中,存储数组的变量始终以 @ 字符开头;在 Python 中,变量可以任意命名,Python 会在内部跟踪数据类型。 |
![]() |
|
Python 中的列表比 Java 中的数组强大得多(尽管如果你真的只想把它当作数组使用,它也可以作为数组使用)。一个更好的类比是 ArrayList 类,它可以容纳任意对象,并且可以在添加新项目时动态扩展。 |
![]() |
|
在 2.2.1 版本之前,Python 没有单独的布尔数据类型。为了弥补这一点,Python 在布尔上下文中(例如 if 语句)接受几乎任何值,规则如下:
|
![]() |
|
元组可以转换为列表,反之亦然。内置的 tuple 函数接受一个列表并返回一个具有相同元素的元组,而 list 函数接受一个元组并返回一个列表。实际上,tuple 冻结列表,而 list 解冻元组。 |
![]() |
|
当使用行连接标记(“\”)将命令拆分到多行时,续行可以以任何方式缩进;Python 通常严格的缩进规则不适用。如果你的 Python IDE 自动缩进了续行,你应该接受其默认设置,除非你有充分的理由不这样做。 |
![]() |
|
Python 中的字符串格式化使用与 C 中的 sprintf 函数相同的语法。 |
![]() |
|
join 仅适用于字符串列表;它不执行任何类型强制转换。连接包含一个或多个非字符串元素的列表将引发异常。 |
![]() |
|
anystring.split(delimiter, 1) 是一种有用的技术,当你想要在字符串中搜索子字符串,然后处理子字符串之前(最终位于返回列表的第一个元素中)和之后(最终位于第二个元素中)的所有内容时,可以使用此技术。 |
![]() |
|
调用函数唯一需要做的事情是为每个必需参数指定一个值(以某种方式);你以何种方式和顺序执行此操作取决于你。 |
![]() |
|
Python 附带了优秀的参考手册,您应该仔细阅读以了解 Python 提供的所有模块。但与大多数语言不同的是,您需要参考手册或手册页来提醒自己如何使用这些模块,而 Python 在很大程度上是自文档化的。 |
![]() |
|
lambda 函数是一个风格问题。使用它们并非必需;在任何可以使用它们的地方,您都可以定义一个单独的普通函数并改用它。我在想要封装特定的、不可重用的代码而不希望用许多小的单行函数来污染我的代码的地方使用它们。 |
![]() |
|
在 SQL 中,您必须使用 IS NULL 而不是 = NULL 来比较空值。在 Python 中,您可以使用 == None 或 is None,但 is None 更快。 |
![]() |
|
Python 中的 from module import * 类似于 Perl 中的 use module;Python 中的 import module 类似于 Perl 中的 require module。 |
![]() |
|
Python 中的 from module import * 类似于 Java 中的 import module.*;Python 中的 import module 类似于 Java 中的 import module。 |
![]() |
|
谨慎使用 from module import *,因为它会使确定特定函数或属性的来源变得困难,从而增加调试和重构的难度。 |
![]() |
|
Python 中的 pass 语句类似于 Java 或 C 中的一组空大括号 ({})。 |
![]() |
|
在 Python 中,类的祖先类名后紧跟括号列出。没有像 Java 中的 extends 这样的特殊关键字。 |
![]() |
|
按照惯例,任何 Python 类方法的第一个参数(对当前实例的引用)都被称为 self。此参数在 C++ 或 Java 中扮演着保留字 this 的角色,但 self 在 Python 中不是保留字,而仅仅是一个命名惯例。尽管如此,请不要将其命名为 self 以外的任何名称;这是一个非常强的惯例。 |
![]() |
|
__init__ 方法是可选的,但当您定义一个方法时,您必须记住显式调用祖先的 __init__ 方法(如果它定义了一个)。更普遍的情况是:每当后代类想要扩展祖先类的行为时,后代类方法必须在适当的时间用适当的参数显式调用祖先类方法。 |
![]() |
|
在 Python 中,只需像调用函数一样调用类即可创建该类的新实例。没有像 C++ 或 Java 中那样的显式 new 运算符。 |
![]() |
|
在 Windows 上的 ActivePython IDE 中,您可以通过选择 -> (Ctrl-L) 快速打开库路径中的任何模块。 |
![]() |
|
Java 和 Powerbuilder 支持按参数列表进行函数重载,即 一个类可以有多个同名但参数数量不同或参数类型不同的方法。其他语言(最著名的是 PL/SQL)甚至支持按参数名称进行函数重载;即 一个类可以有多个同名、参数数量相同、参数类型相同但参数名称不同的方法。Python 不支持这两种方法中的任何一种;它没有任何形式的函数重载。方法仅由其名称定义,并且每个类中只能有一个具有给定名称的方法。因此,如果后代类有一个 __init__ 方法,它总是会覆盖祖先的 __init__ 方法,即使后代类使用不同的参数列表定义它。同样的规则也适用于任何其他方法。 |
![]() |
|
Python 的原作者 Guido 对方法重写的解释如下:“派生类可以覆盖其基类的方法。因为方法在调用同一个对象的其它方法时没有特殊权限,所以一个基类的方法调用同一个基类中定义的另一个方法,实际上可能会调用一个覆盖它的派生类的方法。(对于 C++ 程序员来说:Python 中的所有方法实际上都是虚方法。)” 如果您对此感到困惑(这让我感到困惑),请随意忽略它。我只是想把它传递下去。 |
![]() |
|
始终在 __init__ 方法中为实例的所有数据属性分配初始值。这将为您节省以后数小时的调试时间,跟踪 AttributeError 异常,因为您引用的是未初始化的(因此是不存在的)属性。 |
![]() |
|
在 2.2 之前的 Python 版本中,您不能直接继承内置数据类型,如字符串、列表和字典。为了弥补这一点,Python 提供了模拟这些内置数据类型行为的包装类:UserString、UserList 和 UserDict。通过结合使用普通方法和特殊方法,UserDict 类可以很好地模拟字典。在 Python 2.2 及更高版本中,您可以直接从内置数据类型(如 dict)继承类。本书附带的示例中给出了一个示例,位于 fileinfo_fromdict.py 中。 |
![]() |
|
在类中访问数据属性时,需要限定属性名称:self.attribute。在类中调用其他方法时,需要限定方法名称:self.method。 |
![]() |
|
在 Java 中,您可以使用 str1 == str2 来确定两个字符串变量是否引用同一个物理内存位置。这被称为对象标识,在 Python 中写为 str1 is str2。要在 Java 中比较字符串值,可以使用 str1.equals(str2);在 Python 中,可以使用 str1 == str2。那些被教导相信世界会变得更美好,因为 Java 中的 == 是按标识而不是按值进行比较的 Java 程序员,可能很难适应 Python 缺乏这种“陷阱”的情况。 |
![]() |
|
虽然其他面向对象语言只允许你定义对象的物理模型(“此对象有一个 GetLength 方法”),但 Python 的特殊类方法(如 __len__)允许你定义对象的逻辑模型(“此对象有一个长度”)。 |
![]() |
|
在 Java 中,静态变量(在 Python 中称为类属性)和实例变量(在 Python 中称为数据属性)都在类定义之后立即定义(一个使用 static 关键字,一个不使用)。在 Python 中,这里只能定义类属性;数据属性在 __init__ 方法中定义。 |
![]() |
|
Python 中没有常量。如果你足够努力,一切都可以改变。这符合 Python 的一个核心原则:应该阻止不良行为,但不应该禁止。如果你真的想改变 None 的值,你可以这样做,但当你无法调试代码时,不要来找我。 |
![]() |
|
在 Python 中,所有特殊方法(如 __setitem__)和内置属性(如 __doc__)都遵循一个标准的命名约定:它们都以两个下划线开头和结尾。不要用这种方式命名你自己的方法和属性,因为这只会让你(和其他人)在以后感到困惑。 |
![]() |
|
Python 使用 try...except 处理异常,使用 raise 生成异常。Java 和 C++ 使用 try...catch 处理异常,使用 throw 生成异常。 |
![]() |
|
只要有可能,就应该使用 os 和 os.path 中的函数来进行文件、目录和路径操作。这些模块是特定于平台的模块的包装器,因此像 os.path.split 这样的函数可以在 UNIX、Windows、Mac OS 以及 Python 支持的任何其他平台上工作。 |
![]() |
|
没有办法以编程方式确定两个正则表达式是否等价。你能做的最好的事情是编写大量的测试用例,以确保它们在所有相关输入上表现一致。我们将在本书后面讨论编写测试用例的更多内容。 |
![]() |
|
Python 2.0 有一个 bug,即 SGMLParser 根本无法识别声明(handle_decl 永远不会被调用),这意味着 DOCTYPE 会被静默忽略。这在 Python 2.1 中已修复。 |
![]() |
|
在 Windows 上的 ActivePython IDE 中,你可以在“运行脚本”对话框中指定命令行参数。多个参数之间用空格分隔。 |
![]() |
|
HTML 规范要求所有非 HTML(如客户端 JavaScript)都必须包含在 HTML 注释中,但并非所有网页都能正确执行此操作(并且所有现代网络浏览器如果未包含,也会予以谅解)。BaseHTMLProcessor 不会谅解;如果脚本嵌入不正确,它将被解析为 HTML。例如,如果脚本包含小于号和等号,SGMLParser 可能会错误地认为它找到了标签和属性。SGMLParser 始终将标签和属性名称转换为小写,这可能会破坏脚本,并且 BaseHTMLProcessor 始终将属性值括在双引号中(即使原始 HTML 文档使用单引号或不使用引号),这肯定会破坏脚本。始终在 HTML 注释中保护你的客户端脚本。 |
![]() |
|
Python 2.2 引入了一个微妙但重要的变化,它影响了命名空间搜索顺序:嵌套作用域。在 2.2 之前的 Python 版本中,当你在 嵌套函数 或 lambda 函数 中引用变量时,Python 将在当前(嵌套或 lambda)函数的命名空间中搜索该变量,然后在模块的命名空间中搜索。Python 2.2 将在当前(嵌套或 lambda)函数的命名空间中搜索该变量,然后在父函数的命名空间中搜索,然后在模块的命名空间中搜索。Python 2.1 可以采用任何一种方式工作;默认情况下,它的工作方式与 Python 2.0 相同,但你可以在模块顶部添加以下代码行,使你的模块像 Python 2.2 一样工作from __future__ import nested_scopes |
![]() |
|
使用 locals 和 globals 函数,你可以动态获取任意变量的值,将变量名作为字符串提供。这反映了 getattr 函数的功能,该函数允许你通过提供函数名作为字符串来动态访问任意函数。 |
![]() |
|
将基于字典的字符串格式化与 locals 一起使用,可以方便地提高复杂字符串格式化表达式的可读性,但这是有代价的。调用 locals 会导致性能略有下降,因为 locals 会构建 本地命名空间的副本。 |
![]() |
|
包是一个包含特殊文件 __init__.py 的目录。__init__.py 文件定义了包的属性和方法。它不需要定义任何内容;它可以只是一个空文件,但它必须存在。但是,如果 __init__.py 不存在,则该目录只是一个目录,而不是一个包,并且它不能被导入或包含模块或嵌套包。 |
![]() |
|
本节可能会让人有些困惑,因为有些术语重叠。XML 文档中的元素具有属性,Python 对象也具有属性。当你解析 XML 文档时,你会得到一堆表示 XML 文档所有部分的 Python 对象,其中一些 Python 对象表示 XML 元素的属性。但是,表示(XML)属性的(Python)对象也具有(Python)属性,这些属性用于访问该对象表示的(XML)属性的各个部分。我告诉过你这很让人困惑。我乐于接受关于如何更清楚地区分这些内容的建议。 |
![]() |
|
与字典一样,XML 元素的属性没有顺序。属性在原始 XML 文档中可能以特定顺序列出,并且在将 XML 文档解析为 Python 对象时,Attr 对象可能以特定顺序列出,但这些顺序是任意的,不应具有任何特殊含义。你应该始终按名称访问各个属性,就像字典的键一样。 |
![]() |
|
在这些示例中,HTTP 服务器同时支持 Last-Modified 和 ETag 标头,但并非所有服务器都支持。作为 Web 服务客户端,你应该准备好同时支持两者,但你必须进行防御性编码,以防服务器只支持其中之一或两者都不支持。 |
![]() |
|
unittest 包含在 Python 2.1 及更高版本中。Python 2.0 用户可以从 pyunit.sourceforge.net 下载。 |
![]() |
|
全面的单元测试可以告诉你的最重要的事情是什么时候停止编码。当函数的所有单元测试都通过时,停止编码该函数。当整个模块的所有单元测试都通过时,停止编码该模块。 |
![]() |
|
当你的所有测试都通过时,停止编码。 |
![]() |
|
无论何时,只要您要多次使用同一个正则表达式,就应该将它编译成一个模式对象,然后直接调用该模式对象的方法。 |
![]() |
|
传递给 os.path.abspath 的路径名和文件名不需要一定存在。 |
![]() |
|
os.path.abspath 不仅会构造完整的路径名,还会对其进行规范化。这意味着,如果您位于 /usr/ 目录中,则 os.path.abspath('bin/../local/bin') 将返回 /usr/local/bin。它通过尽可能简化路径来规范化路径。如果您只想规范化这样的路径名而不将其转换为完整路径名,请改用 os.path.normpath。 |
![]() |
|
与 os 和 os.path 模块中的其他函数一样,os.path.abspath 也是跨平台的。如果您在 Windows(使用反斜杠作为路径分隔符)或 Mac OS(使用冒号)上运行,则结果将与我的示例略有不同,但它们仍然有效。这就是 os 模块的意义所在。 |
![]() |
|
您可以在命令行上使用 timeit 模块来测试现有的 Python 程序,而无需修改代码。有关命令行标志的文档,请参阅 https://docs.pythonlang.cn/lib/node396.html。 |
![]() |
|
仅当您已经知道需要优化哪些代码时,timeit 模块才有效。如果您有一个更大的 Python 程序,并且不知道性能问题出在哪里,请查看 hotshot 模块。 |
<< 5 分钟回顾 |
| | |
示例列表 >> |