Python拾零于《 Python编程金典》读书笔记ch1-7


可以说是有经验的Python专家给出的编程要点的集合,这里使用了性质-类别方式列举:

先列出所有性质:
  
[url=#gold_ch1_7_1]知识点[/url]
[url=#gold_ch1_7_2]良好的编程习惯[/url]
[url=#gold_ch1_7_3]测试和调试提示[/url]
[url=#gold_ch1_7_4]移植性提示[/url]
[url=#gold_ch1_7_5]软件工程知识[/url]
[url=#gold_ch1_7_6]性能提示[/url]
  和类别:
  1. 绪论
2. python编程概述
3. 控制流程
4. 函数
5. 列表、元组和字典
6. 公共网关接口(CGI)入门
7. 基于面向对象的编程
  
正文:
  知识点 (概述)
python是一种区分大小写的语言。
id函数返回变量内存位置,type函数返回变量类型。


在python2.2前,只提供一种除法运算符(/),运算的行为(即是Floor整数除法,还是 True浮点除法)是由操作数的类型来决定的。如果操作数全是整数,就执行Floor除法。如一个或两个操作数是浮点数,就执行True浮点除法。

在python 2.2后的所有版本中,设计者决定去除(/)的随意性。决定采用两个操作符,其中/执行True除法;//执行Floor除法。但这样会造成旧版本的程序出错,所以设计者采取了一种折衷的办法。如果不先声明,python还是使用旧的/操作符。如果要使用新的方法就要 进行声明,声明方式是: from __future__ import division,这样就可以用/ 和 //了。
(函数)
函数定义中创建的所有变量都是"局部变量"--只存在于声明它们的函数中。

python定义了3个命名空间,分别是局部(local),全局(global)和内建(built-in)。程序访问标识符的值时,python会按特定顺序搜索命名空间(即按局部,全局和内建顺序)。

重复使用重复的结构,如for和while;递归使用选择结构,如if和if/else。之间的差别是,重复采用一个重复结构,而递归采用重复的函数调用。两者都要进行终止测试:重复会在循环继续条件为false时终止;递归在识别出基本条件是终止。由计数器控制的重复和递归都是逐渐终止:重复会不断改变一个计数器,直到计数器的值使循环继续条件变为false;递归则不断对原始问题进行简化,直到抵达基本条件。重复和递归都可无休止地进行:如果循环继续检测永远都不能变成false,会发生无限循环;如果递归调用永远不能将问题简化 成基本条件,会发生无穷递归。

(CGI)
CGI可用于几乎任何程序语言或脚本语言,比如C,PERL和PYTHON。

最常见的HTTP请求类型是GET AND POST。这些请求从WEB服务器获取资源,并将客户表单数据发送给WEB服务器。get请求将表单内容作为URL的一部份发送。大多数 WEB服务器将GET请求查询字符串限制在1024个字符以内。如果查询字符串超过这个限制,就必须使用POST请求。POST请求中发送的数据不是 URL的一部份,用户看不到它们。如果表单包含许多字段,那通常由POST请求进行提交。一些敏感的表单字段,如用户名和密码,也通常使用这种请求类型来发送。GET请求的最简单形式的格式为GET /books/downloads.html HTTP/1.1。服务器收到请求后,会发送一个HTTP标头,如 Content-type:text/html。表明MIME类型,然后服务器发送请求的HTML/XHTML文档中文本 (DOWNLOADS.HTML)。

web应用程序采用两类脚本编程,服务器端和客户端。CGI脚本是服务器端脚本的一个例子,客户端脚本的一个例子是javascript。
(OOP)
在过程式语言中,基本编程单元是"函数",在面向对象语言中,基本编程单元是"类",最终要通过它来实例化(即创建)对象。

__init__方法是类的"构造函数"方法。每次创建类的一个对象时,都会执行它的构造函数。它会初始化对象属性,并返回None。
包括构造函数在内的所有方法至少要指定一个参数。该参数代表要调用其方法的类的对象。人们常把这个参数称为"类实例对象"。但由于这术语容易混淆,所以我们将任何方法的第一个参数都称为"对象引用参数",或简称"对象引用"。方法必须通过对象引用来访问从属于类的属性以及其它方法。按照约定,对象引用参数称为self。

类的特殊属性:
__bases__ 包含基类的一个元组,类可以从这些基类直接继承。如果类不从其他类继承,元组就会为空。
__dict__ 与类的命名空间对应的一个字典。其中每个键-值对都代表在命名空间中的一个标识符及其值。
__doc__ 类的文档字符串。如果类没有指定文档化字符串,值为None。
__module__ 包含模块(文件)名的一个字符串,类定义于这个模块中。
__name__ 包含类名的一个字符串。

在C++和java等程序语言中,类可明确指出类的客户能访问哪些属性或方法。这些属性或方法被认为是"公共"的。不能由类的客户访问的属性和方法则被认为是私有的。在python 中,对象的属性是肯定能访问的--没有办法阻止其它代码访问数据。然而,python提供一种特别的机制来防止任意访问数据。在属性名附加双下划线前缀。 python解释器会对属性执行 "名称重整"。如self.__hour,python会创建一个_Classname__hour的属性。但它一样是可访问的,只是名字变了。
构造函数也可以定义默认参数,从而在客户没有指定参数的前提下,为对象属性指定初始值。还可以定义关键字参数。

析构函数__del__是构造函数__init__的相反,用于执行"终止清理",然后由解释器回收对象的内存,使内存能被重用。析构函数通常只指定 self参数,并返回None。

类的每个对象都拥有在构造函数中创建的所有属性的拷贝。特定情况下,类的所有对象只能共享属性的一个拷贝。为此要使用"类属性"。它是"类范围"的信息(也就是说,它是类的一个属性,而非类的特定对象属性)。它可节省空间和时间,提高性能。为访问类属性,只需为属性名附加类名前缀,再加一个小数点即可。(Classname.xxx)
  
良好的编程习惯  
(概述)
有意义的变量名可改善程序的"自编档能力",也就是说,只需读一读程序,就能轻松理解它。

避免标识符以下划线和双下划线开头,因为python解释器可能保留了那些名称,供内部使用。

在二元运算符两端添加一个空格。这样可以突出运算符,增强程序的可读性。

(函数)
尽快熟悉核心python模块提供的函数和类集合。

避免变量名遮蔽外层作用域中的名称。为此,要注意避免标识符与内建命名空间中的标识符同名,并避免在程序中使用重复的标识符。

使用默认参数可简化函数调用的编写,但有的程序员认为,显式指定所有参数会使程序更易读。


(OOP)
文档化字符串习惯上是一个三引号字符串。这样可以在不改变引号样式的前提下,扩展一个程序的文档(例如添加更多的行)。
  
尽可包含文档化字符串,使程序更有条理。

将所有方法的第一个参数都命名为self。始终遵循这一命名约定,可确保不同程序员编写的python程序是一致的。

属性名以单下划线开头,虽然在python语法中没有特殊的含义,但单下划线是python 程序员使用类时约定使用的符号,表明程序员不希望类的用户直接访问属性。以单划线开头的属性揭示一个类的接口的相关信息。类如果定义了此类属性,它的客户就只能通过类提供的访问方法来访问并修改属性值。如果不是这样做,通常会导致程序执行期间出现不可预料 的错误。

直接访问对象的属性可能导致数据进入不一致状态。一个办法是让类提供"访问方法",通过一种得到精心控制的方式来读写类数据。

   测试和调试提示  
(概述)
使用 -i 选项(python -i test.py)。会导致编译器在执行了文件中的语句后进行交互模式,这非常适用于调试程序。

为了避免难以察觉的错误,务必在程序中采用统一和正确的缩进。


即使提供了访问方法,也无法自动确保数据完整性,程序员必须提供有效性验证。


(OOP)
忘记将对象引用(通常是self参数)设为方法定义中的第一个参数,会导致该方法在运 行时被调用时,造成严重逻辑错误。


如果忘记在方法内部通过对象引用(通常称为self)来访问由对象的类定义的另一个方法,就会导致严重的运行时错误或者逻辑错误。如全局命名空间包含的一个函数与类的某个方法同名,就会产生逻辑错误。此时,如果忘记通过对象引用来访问方法名,实际会调用全 局函数。
移植性提示 (函数)
使用核心python模块中的函数,通常可使用程序更易移植。
  软件工程知识  
(控制流程)
经验表明,用计算机解决问题最有效的办法是为解决方案开发一种算法。一旦开发出正确的算法,通常能根据它方便地生成一个能实际工作的python程序。

在从事大型的、复杂的项目时,一定要开发算法。这样才可能不会导致严重错误,从而 推迟项目进度。


(函数)
避免重复别人的劳动。尽量使用标准库模块函数,不要写新函数。这样可加快程序开发进度,并增强可靠性。因为你所使用的是经良好设计和测试的代码。


每个函数都应该只限执行单一的、良好定义的任务,函数名应清楚地描述那个任务。


如果实在想不出能准确表达函数作用的名称,就表明函数可能执行了太多的分散任务,通常,最好把这种函数分解成多个更小的函数。


程序应写为若干个小函数的集合。这样使程序更易编写、调试、维护和修改。


如函数需要大量的参数,表明它执行的任务可能过多。请考虑将函数分解成更小的函数,令其执行单独的任务。函数的def语句尽可能不超过一行。


采用递归方式能解决的任何问题也可采用重复方式(非递归方式)解决。如果递归方式能够更自然地反映问题,并使程序易于理解和调试,通常应该首选递归方式。通常,只需几行代码就可完成一个递归方式,重复方式则相反,它需要大量的代码来实现。选择递归的另一个原因是,重复方案也许不是很直观。


采用清晰的、层次清楚的方式对程序进行"函数化",有助于保证良好的软件工程,但性能上要付出一定代价。

(OOP)
本书的中心思想是"重用,重用,再重用"。我们的重点是"创建宝贵的类",创造有价值的"软件资产"。

先初始化对象,再让客户代码调用对象的方法。不能依赖客户代码正确初始化对象。

利用访问方法控制对属性的访问(尤其是写访问)有助于确保数据完整性。

python的类和模块化机利于程序的独立实现。如果代码所用的一个类的实现发生了改变, 这段代码是无需更改的。

并不是所有的方法都要作为类的接口的一部份。有的方法是类的其它方法的一种实用方法,不准备供类的客户使用。

将客户不应该访问的任何数据设为私有。

如果类的一个方法提供了构造函数(或其他方法)需要的全部或部份功能,请从构造函数(或其他方法)中调用那个方法。这样可简化代码的维护,并减少代码的实现改变后出错 的可能。一个通用规则是:避免重复代码。

合成是软件重用的一种形式,即类的成员引用了其他类的对象。

在类成员引用了另一个类的对象的前提下,使那个成员对象能被公共访问,不但没有违反封装性,而且还可隐藏那个成员对象的私有成员 性能提示 (函数)
不要试图改写现成的模块函数使其更高效,因为这些函数已非常完美了。
一般不要编写会造成调用次数成指数级增加的"斐波拉契"式递归程序。

避免对性能要求高的时候使用递归。递归调用既费时、又耗内存。

一个由多个函数构成的程序,与一个没有任何函数的一体式程序相比,会产生大量的函数调用,这些函数调用会占用大量的处理器时间和内存。但另一方面,一体式程序的编程、测试、调试和维护都比较复杂。因此对程序进行函数化时要综合考虑。保证能兼顾良好的性 能和软件工程。

  
(OOP)
链式比较表达式(0 = 0 and a

如果数据的一个拷贝已经够用,请用类属性以节省空间。