OReilly.Learning.Python.3rd.Edition.Oct.2007
PiscesSTAR
|
1#
PiscesSTAR 发表于 2008-07-21 13:50
OReilly.Learning.Python.3rd.Edition.Oct.20077 / 21 / 2008 import this 显示Python的设计原则 source(*.py) ---> bytecode(*.pyc) ---> PVM 若是python在.py所在目录有写权限,则执行完会产生.pyc文件,下次执行时会直接使用.pyc文件,除非.py文件被修改了(通过时间戳比较,类似于make程序^^);若是没有写权限,则.pyc存在于内存中 .pyc文件可以加快执行速度 可以将所有.py文件翻译为.pyc文件后打包发布,Python乐意使用.pyc文件,可以加快执行速度 只保存被import的文件的字节码;嵌套的import的文件也会被执行并生成字节码,只有top-level文件的字节码不保存 将python程序做成二进制文件实际上是将程序的字节码文件、PVM和支持库打包。因为python程序是在PVM上运行的,所以不像传统语言的二进制文件运行那么快,并且二进制文件要大一些 所有以.py结尾的源文件都可看作是module import会找到文件、将其转换为字节码文件(import会导致生成.pyc文件)、最后执行。import的目标优先是.pyc文件。嵌套的import的文件也会被执行并生成字节码,只有top-level文件的字节码不保存 import最终会执行module,执行module时生成attributes reload处理的module应该已经import过 reload是函数,而import是statement。reload返回载入的module对象的一个描述 在一个进程中,若是.py文件修改过,则reload会重新加载;而import会使用旧的.pyc文件(内存中),因为import代价比较大 attribute是一个绑定到特定对象的变量名,例如函数名 from复制模块的attribute,这样它们就成了调用者的变量 execfile('module.py')会加载执行代码,但是它更像将代码粘贴到调用点执行,而不是import模块;因此,它可能会潜在地修改调用者的变量 module search path = stardard dirs + PYTHONPATH => sys.path 在Python中的赋值会产生对对象的引用,而不是copy bytecode + PVM + support files = frozen binary module(.py) --- namespace --- attributes ---> import ---> execute 7 / 23 / 2008 Python中所有东西都是对象,小到简单数据类型,大到程序代码 Python程序中处理的任何事物都是一种对象 Python的类型是动态的,它自动跟踪类型而不是使用声明;但它也是强类型的,在特定类型对象上只能进行限定的操作 Python中没有类型声明,表达式决定了对象的类型 import math import random s[:] top-level复制 number、string、tuple是immutalbe的,而list和dictionary是mutable string对象有自己的方法,不管方法名字怎样,string对象都是immutable的,例如replace() s.find('str') s.replace('s', 'r') s.split('delimiter') s.upper() s.isalpha() s.rstrip() ord('c') re list + listx 生成新的list,不会改变原有的list list.append 改变原有的list list.pop(index) list.sort() list.reverse() 虽然list的大小不固定,但是不允许越界访问 list是mutable的,而且元素类型可以不同。list的元素可以变化,其本身也可以增大或缩小。虽然list的大小没有限制,但是当前list对象的大小是固定的,要增大只能通过append方法,越界赋值是不允许的 [expression looping-construct] => list comprehension Python中,interger的精度同C中的long,而floating-point的精度同C中的double;python会在integer溢出时将其自动转换为long型 在内部,复数以floating-point对的形式出现 Python3.0中,integet会同long统一成没有精度限制的integer 在python中,变量不需要提前声明,但是在使用前必须初始化 Python支持位操作,但是在python中推荐使用其他方法对信息进行存储 在Python中,不要将一串数字以0开头,它会被看作是8进制数,会导致行为不像你想的那样 dictionary可以自由扩充,是mutable的,不像list那样有越界限制,但是若是查找时key不存在也会报错 d.keys() d.has_key('key') setX &/|/- setY 集合类型 decimal对象可以指定固定精度 import decimal None type可以检测对象类型,但是不推荐这样做,会限制处理范围,失去python的动态类型处理的特点 Python会自动回收内存,具有垃圾回收机制 Python将内置函数放于模块__builtin__中 通过将一个序列或者其他可遍历对象传给函数set可以创建一个set对象 True和False是bool类型的实例,即它们也是对象 赋值操作实际上是将对象绑定到变量 raw string的最后一个字符不能是\,可以如此表示 r'str''\\' string.Template('str') template.substitute(key=value) template.substitute(dict) string.maketrans str.translate dict.copy top-level复制 deepcopy(dict) 完全复制 dict.get(key) 若是不存在就返回NULL,而不会报错 print最后一个参数的后面添加‘,’,则下一个print语句将在同一行继续输出 sequence unpacking中变量的数量与目标的数量应该一致 exec执行语句,eval计算表达式的值 input = eval(raw_input(...)) zip(seq1, seq2, ...) 创建适合并行遍历的新的序列 函数可以返回多个值,例如将它们保存到tuple/list中返回 在函数起始部分的字符串会被看作是docstring,可以通过func.__doc__访问,或者help(func) 任何时候,变量保存的都是对象引用,可以通过引用改动mutable对象,或者改变引用 位置参数 关键字参数 虽然输入多了一些,但是可以清晰每个参数的作用,而且不用受参数顺序限制 缺省参数 关键字参数可以和缺省参数一起使用;关键字参数也可以与位置参数一起使用,但是调用时位置参数要在关键字参数前面,否则解释器不知道如何匹配 *参数、**参数 定义或者调用函数时通过使用*或者**参数可以容易地传递元组或者词典 python的源文件可以通过编码使用ASCII以外的字符集,最好的方法是在#!行后面用一个特殊的注释行来定义字符集: # -*- coding: encoding -*- 根据这个声明,python会尝试将文件中的字符编码转为encoding编码,并且它尽可能的将指定的编码直接写成unicode文本。在python库参考手册中codecs部份可以找到可用的编码列表;根据个人经验,推荐使用cp-936或utf-8处理中文。 使用UTF-8内码(无论是用标记还是编码声明),可以在字符串和注释中使用世界上的大部分语言。标志符中不能使用非ASCII字符集。 *表示收集剩余的位置参数;对于关键字参数需要使用** lambda 参数列表:语句 map(函数,序列,[seq]...) filter(函数,序列) list comprehension reduce(函数,序列) apply(函数,[元组参数[,词典参数]]) 由于*和**,已经过时 要将类的方法或者属性设置为private,则名字以__开头;在内部,这种名字被翻译成_class-name__name,那么通过class/object._class-name__name还是可以访问 以_开头的名字不会通过from module import *被import 可以通过class的__base__属性获取其baseclass 对于多继承,若是一个方法由多个超类实现,则最终使用的是声明靠前的父类的方法 callable() getattr(object, name[, default]) hasattr(object, name) setattr(object, name, value) isinstance(object, class) issubclass(A, B) python使用异常对象来描述异常,若是异常不被处理,则程序终止并打印trackback raise SomeClass[, 'str'] 自动创建一个instance raise someObject import exceptions dir(exceptions) 7 / 24 / 2008 常用异常 Exception AttributeError IOError IndexError KeyError NameError SyntaxError TypeError ValueError ZeroDivisionError __metaclass__ = type __init__ 构造函数 __del__ 析构函数(尽量不使用) 重载构造函数,需要显示调用super的构造函数,否则对象初始化不完整 def __init__(self[,...]): BaseClass.__init__(self[,...]) def __init__(self[,...]): super(CurrentClass, self).__init__([...]) __len__(self): __getitem__(self, key): __setitem__(self, key, value): __delitem__(self, key): staticmethod(smeth) smeth不需要参数self classmethod(cmeth) cmeth需要参数cls @staticmethod @classmethod property __getattribute__(self, name) __getattr__(self, name) __setattr__(self, name, value) __delattr__(self, name) def __iter__(self): yield generator是一个包含关键字yield的函数 if __name__ == '__main__': sys.path PYTHONPATH package中必须有一个模块__init__.py module.__all__定义模块的公共接口,from module import *只能获取__all__中的属性 module.__file__ 模块的存放路径 import webbrowser import fileinput import sets import heapq import collections import time import shelve import re 变量在第一次赋值时创建;变量没有类型,只是简单地指向有类型的对象 变量是系统表中的表项,每个表项还有用于连接对象的空间;对象是一块分配的内存,存放了值;引用是变量对对象的指针 对象的结构比较复杂,需要记录对象的类型以及引用计数等 变量没有类型,对象才有类型,变量只是一个名字与引用的组合;变量在特定时间引用了特定的对象 一个变量可以指向任意类型的对象 对象的引用计数支持了自动回收机制 复制一个list的最常用的方式是nl = l[:] Python会缓存小的integer和小的string,而大多数对象在不用时立即回收 import sys sys.getrefcount() 在Python中,零字节\0(null)不能终止一个字符串,实际上,python中没有字符串终止字符。字符串文本和长度都存放在内存中 若是python不能识别\后面的转义序列,则将\作为字符保存在字符串中\\ Python中的字符串不需要提前分配空间,而C中需要 Python中不能通过+来混合数字和字符串 格式化输出时,若有多个输出值,要将其组成tuple 任意类型对象都可以转化为string,任意类型对象都可以使用%s格式化输出 对于基于模式的文本处理,要使用re模块 建议使用string类的方法,而不是string模块,string模块deprecated 每一个Python模块有一个内置变量__name__,若是模块作为程序运行则该变量被设置为__main__,若是import则不会。该特点有利于编写可重用的代码,可以将代码组织为函数,既能import也能执行 list可以看作是对象引用的数组,类似于C中的指针数组 因为list存放的是对象引用,所以在改动list时会影响对象的引用计数 list.append() + list.pop() ---> stack dictionary可以看作是对象引用的hash表 dictionary是无序的,所以不能直接使用for,可以通过d.keys()控制遍历 tuple类似于list,但是immutable 变量存放的是对象的引用,通过变量修改对象可能会影响到对象的其他引用 COPY: l[:] d.copy() 只是最上层的复制 import copy copy.deepcopy() 全面复制 任何immutable对象都可以成为词典的key tuple、list、dictionary中存放的都是对象的引用 7 / 25 / 2008 with/as from __future__ import with_statement 对于单个block,所有语句的缩进必须相同,否则就是语法错误 ()、[]、{}中的语句可以占据多行,语句不会终止除非遇到闭包对 隐式赋值:import、from、def、class、for、function arguments tuple/list unpacking assignments sequence assignments tuple assignment是交换变量值的好方式 sequence assignment有着很复杂的使用方式,但是code非常漂亮 +=进行原地改动,而不是像+创建一个新的对象,所以效率要好一些;注意共享引用的影响 import操作后模块名就成为了调用者的变量 from module import *不会获取以单下滑线开头的变量_X __X__类型的变量有特殊含义 __X类型的变量是局部与闭包的class的 单下滑线_记录了交互工作时最后一个表达式的结果 print >> fileobj, ... iterator StopIteration iterator = iter(obj) iterator.next() __iter__ __getitem__ range zip/map zip(key, value) for (k, v) in zip(keys, values): d[k] = v dict(zip(keys, values)) for (offset, item) in enumerate(sequence) generatorobj = enumerate(s) generatorobj.next() list comprehension可以有多个for loop,其类似于与普通的嵌套for,但是运行更快 docstring要出现在描述的module、function或者class的可执行语句之前,python会自动识别这些描述,将它们写入对应对象的__doc__属性 def是可执行语句,直到运行到def函数才被创建。def可以与其他可嵌套结构进行嵌套 def创建一个函数对象,并给其赋名。由于函数也是对象,而变量没有类型,所以可以有多个函数名对应一个函数 参数传递传递的对象引用,所以在改变参数时要注意不要影响调用者 Python中的一切都是runtime的,所以函数对象的创建也是动态的 def在运行时才创建函数,因为def是一个语句,所以可以出现在语句可以出现的任何地方,例如if结构 由于变量是动态创建的,所以python在运行时根据对其赋值的位置将其绑定到特定的namespace,从而确定其可见范围 在一个函数中定义的变量其namespace位于该函数内,可以与函数外部的变量同名而不发生冲突 在函数外定义的变量在整个文件范围内有效,为global的 一个模块构成了一个全局范围,global变量是模块对象的attribute,可以在模块内作为变量使用 global变量的可见范围为单个模块,若要使用某个模块的global变量,必须进行import操作。当提到global,想到module 函数内部的变量缺省为局部变量,也可以通过res指定。注意变量不是对象 因为函数可以递归调用,所以实际上是一次函数调用创建一个新的局部范围,而不是函数定义创建一个局部范围 任何在函数内部赋值而定义的变量都是局部的:语句、import、def、参数传递等等 变量的可见范围由它被赋值(被创建)的地方决定 交互方式时的所有代码属于模块__main__,所以交互时创建的变量也是存在于模块中 名字解析最多有4个范围:local、函数、global和built-in 由于变量是动态创建的,而且局部变量可以与全局变量同名,所以在一个函数中创建或者改变的变量除非声明为global,否则当作局部变量来处理,不同于同名全局变量 若是仅仅是使用的话可以直接引用外部变量 attribute名字的解析处理方式不同于variable名字 python的简单类型对象是immutalbe的,变量赋值会导致新的对应对象的创建和引用传递 python有垃圾回收功能 python的long只受内存限制,float为双精度,int范围依赖于平台 简单类型也有自己的构造函数 python中所有的数据值都有对应的对象,所以变量赋值实质上是对后台对象引用的转换,对于简单类型对象本身没有变化,变量在特定时间只能指向一个对象,可以通过id函数检测变量引用的对象标识 在Python中,简单数据类型并不是原始数据类型,而是完善的对象,它们有自已的方法和类。另外,这些简单的内置类型是不可改变的,这意味着:创建对象之后,您无法更改对象的值。如果需要新值,则必须创建新的对象 python不存在内置字符数据类型 bool, int, long, float, complex immutable tuple --- immutable --- tuple是一个异构容器 str --- immutable LEGB 尽量不要改动全局变量,在当前模块以及其他模块 工厂函数 factory function 在不使用类的情况下,global变量、工厂函数、缺省参数是函数记住状态信息的主要方式 lambda引入了新的local范围 lambda是表达式 函数或者lambda是动态创建的,它们被调用时才会创建,才会解析变量(按LEGB搜索) def makeActions(): acts = [] for i in range(5): acts.append(lambda x, i=i: i**x) return acts |