Python学习笔记基础
基础
- 语法
#开头,注释- 缩进的语句视为代码块
- 大小写敏感
数据类型和变量
True和False首字母大写and、or和not- 空值:
None
字符串格式化
%%d整数%f浮点数%s字符串%x十六进制整数补位
'%2d-%02d' % (3, 1)' 3-01''%.2f' % 3.1415926'3.14'
数组:
list和tuplelist数组len(list)得到长度list[-2]获得倒数第二个元素list.append(ele)往list中追加元素到末尾list.insert(1, ele),把元素插入到指定的位置,比如索引号为1的位置list.pop(),删除list末尾的元素,用pop()方法list.pop(i)删除指定位置的元素,用pop(i)方法,其中i是索引位置- 元素的数据类型也可以不同,
L = ['Apple', 123, True]
tuple数组:classmates = ('Michael', 'Bob', 'Tracy')tuple一旦初始化就不能修改,代码更安全
条件判断和循环
ifelifelsefor inwhilerange()函数range(1,5) #代表从1到5(不包含5)[1, 2, 3, 4]range(1,5,2) #代表从1到5,间隔2(不包含5)[1, 3]range(5) #代表从0到5(不包含5)[0, 1, 2, 3, 4]raw_inpit(str)读取的内容永远以字符串的形式返回
dict和setdict就是map,用key-value的形式存储。d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}根据
key获得value[]:一旦key不存在就会报错get()函数:如果key不存在,可以返回None,或者自己指定的value(作为第二个参数传入)
set是一组key的集合,但不存储value,key不能重复。- 需要list作为输入
add(key)函数用来往里面添加元素,自动忽略重复remove(key)函数用来删除元素&操作用来做交集|操作用来做并集
函数
Python内置数据类型转换函数:如
int()Python可以给函数赋别名,如:
a = abs定义函数,
def:def my_abs(x):if x >= 0:return xelse:return -x如果没有
return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。空函数,
pass:def nop():pass类型检查,
isinstance:def my_abs(x):if not isinstance(x, (int, float)):raise TypeError('bad operand type')if x >= 0:return xelse:return -xPython函数可以返回多个值:
import mathdef move(x, y, step, angle=0):nx = x + step * math.cos(angle)ny = y - step * math.sin(angle)return nx, nyx, y = move(100, 100, 60, math.pi / 6)print x, y151.961524227 70.0事实上,它并没有返回多个值,而是返回了一个tuple
Python具有默认参数:
def power(x, n=2):s = 1while n > 0:n = n - 1s = s * xreturn s默认参数必须指向不变对象,不然默认参数就会不断变化,例子:
def add_end(L=[]):L.append('END')return Ladd_end()['END']add_end()['END', 'END']add_end()['END', 'END', 'END']可变参数,
*:def calc(*numbers):sum = 0for n in numbers:sum = sum + n * nreturn sumcalc(1, 2)5calc()0在函数内部,参数
numbers接收到的是一个tuple。如果已经有一个list或者tuple,可以这么写:
nums = [1, 2, 3]calc(*nums)14关键字参数:
**,会把多与参数自动组装成一个dict:def person(name, age, **kw):print 'name:', name, 'age:', age, 'other:', kwperson('Michael', 30)name: Michael age: 30 other: {}person('Bob', 35, city='Beijing')name: Bob age: 35 other: {'city': 'Beijing'}person('Adam', 45, gender='M', job='Engineer')name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}kw = {'city': 'Beijing', 'job': 'Engineer'}person('Jack', 24, **kw)name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数
高级特性
切片(Slice )
|
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。- 如果第一个索引是0,还可以省略。
L[-1]取倒数第一个元素,也支持倒数切片:L(-2:)- 只写
[:]就可以原样复制一个list L[:10:2]表示前十个元素,每两个取一个:[0,2,4,6,8]- tuple也可以用切片,操作结果也是tuple
- 字符串也支持切片
迭代(Iteration)
只要是可迭代对象(list,tuple,dict,set,字符串)都可以用
for...in...迭代默认情况下,dict迭代的是key。
- 如果要迭代value,可以用
for value in d.itervalues() - 如果要同时迭代key和value,可以用
for k, v in d.iteritems()。
- 如果要迭代value,可以用
判断一个对象是否是可迭代对象:
from collections import Iterableisinstance('abc', Iterable) # str是否可迭代 Trueisinstance([1,2,3], Iterable) # list是否可迭代 Trueisinstance(123, Iterable) # 整数是否可迭代 False拥有下标的循环:
for i, value in enumerate(['A', 'B', 'C']):print i, valuefor循环同时引用两个变量:for x, y in [(1, 1), (2, 4), (3, 9)]:print x, y
列表生成式(List Comprehensions)
[x * x for x in range(1, 11)]→[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]- 加上判断:
[x * x for x in range(1, 11) if x % 2 == 0]→[4, 16, 36, 64, 100] - 两层循环(可以用来生成全排列):
[m + n for m in 'ABC' for n in 'XYZ']→['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
生成器(Generator)
生成器里面装了用来生成一个list的算法,这样就不必创建完整的list,从而节省大量的空间,一边循环,一边计算。
|
也可以用for循环:
|
定义generator的另一种方法,
yield:# print Fibonacci listdef fib(max):n, a, b = 0, 0, 1while n < max:print ba, b = b, a + bn = n + 1改写成generator:
# Fibonacci generatordef fib(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1fib(6)<generator object fib at 0x104feaaa0>generator的执行顺序:
变成generator的函数,在每次调用
next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。def odd():print 'step 1'yield 1print 'step 2'yield 3print 'step 3'yield 5...o = odd()o.next()step 11o.next()step 23o.next()step 35o.next()Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration
函数式编程(Functional Programming)
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
高阶函数
map第一个参数是函数,第二个参数是可迭代对象,返回一个listreduce第一个参数是函数,第二个参数是可迭代对象,函数的两个参数(result, item)filtersorted第一个参数是可迭代对象,第二个参数是比较函数(有默认值)
返回函数
- Python也有闭包的概念
匿名函数(lambda)
lambda x: x * x等同于:
|
装饰器(Decorator)
@
|
|
相当于执行了:
|
但此时,now.__name__已经被替换成了wrapper,所以完整的写法:
|
偏函数(Partial function)
可以固定某个参数的默认值,比如下方的例子,固定了int函数的base参数。
|
模块
模块:一个文件就是一个模块
包:就是不同的文件夹,但每个包目录下面都要有一个__init__.py的文件,否则就是一个普通目录而不是一个包。__init.__.py可以是空文件,也可以有代码,因为__init__.py本身就是一个模块,它的模块名就是它的父目录。比如如下的文件结构:
文件www.py的模块名就是mycompany.web.www,两个文件utils.py的模块名分别是mycompany.utils和mycompany.web.utils。
引入模块
|
第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;
第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;
第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;
sys.argv用list存储了命令行的所有参数。python hello.py对应['hello.py'],python hello.py Michael对应 ['hello.py', 'Michael]。
最后两行:当用命令行运行hello模块时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,则不会。
别名:
cStringIO是C写的,速度更快,这样就可以优先导入cStringIO。如果有些平台不提供cStringIO,还可以降级使用StringIO。try:import cStringIO as StringIOexcept ImportError: # 导入失败会捕获到ImportErrorimport StringIO还有类似
simplejson这样的库,在Python 2.6之前是独立的第三方库,从2.6开始内置try:import json # python >= 2.6except ImportError:import simplejson as json # python <= 2.5作用域:
前缀
_表示私有函数,不应该被外部引用。
安装第三方模块
pip
pip install是全局安装
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块。搜索路径存放在sys模块的path变量中,可以添加要搜索的目录:
|
__future__模块
Python提供了__future__模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性,比如:
|
|
面向对象编程
|
类和实例
|
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。
__init__函数是构造函数。
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。
访问限制
- 在Python中,实例的变量名如果以
__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。 - 变量名类似
__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。 - 以一个下划线开头的实例变量名,比如
_name,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。 - 双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问
__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
继承与多态
OOP的特性,不作多余解释。
获取对象信息
type()type(123)<type 'int'>type('str')<type 'str'>type(None)<type 'NoneType'>type(abs)<type 'builtin_function_or_method'>type(a)<class '__main__.Animal'>types模块types.StringType、types.UnicodeType、types.ListType、types.TypeType(所有类型本身的类型就是TypeType)isinstance()# object -> Animal -> Dog -> Huskya = Animal()d = Dog()h = Husky()isinstance(h, Husky) # Trueisinstance(h, Dog) # Trueisinstance(h, Animal) # True判断一个变量是否是某些类型中的一种
isinstance('a', (str, unicode)) # Trueisinstance(u'a', (str, unicode)) # Truedir():获得对象的所有属性和方法,返回一个list类似
__xxx__的属性和方法在Python中都是有特殊用途的。比如__len__方法返回长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法:class MyObject(object):def __len__(self):return 100obj = MyObject()len(obj) # 100hasattr、setattr、getattrhasattr(obj, 'x') # 有属性'x'吗?setattr(obj, 'y', 19) # 设置一个属性'y'getattr(obj, 'z') # 获取属性'z'
__slots__
给class绑定新的方法,
MethodType:def set_score(self, score):self.score = scoreStudent.set_score = MethodType(set_score, None, Student)限制类能添加的属性,
__slots:class Student(object):__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称对子类不起作用。
@property
|
|
不定义setter的话,就是一个只读属性
多重继承
|
定制类
__str__()方法用于自动类型转换class Student(object):def __init__(self, name):self.name = namedef __str__(self):return 'Student object (name: %s)' % self.name__iter__(),配合next()方法,可以对类进行for...in操作。class Fib(object):def __init__(self):self.a, self.b = 0, 1 # 初始化两个计数器a,bdef __iter__(self):return self # 实例本身就是迭代对象,故返回自己def next(self):self.a, self.b = self.b, self.a + self.b # 计算下一个值if self.a > 100000: # 退出循环的条件raise StopIteration();return self.a # 返回下一个值for n in Fib():print n__getitem__():可以类似list那样,用方括号[]取出对应的元素。class Fib(object):def __getitem__(self, n):a, b = 1, 1for x in range(n):a, b = b, a + breturn af = Fib()f[0] # 1f[1] # 1f[10] # 89f[:10] # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]f[:10:2] # 未对step做处理,[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]__getitem__()也没有对负数进行处理。__getitem__()也可以将对象处理成一个dict:class Test(object):def __init__(self, a, b):self.a = aself.b = bdef __getitem__(self, n):if n == 'a':return self.aelse:return self.bf = Test('aa', 'bb')print f['a'] # 'aa'与之对应的是
__setitem__()方法,把对象视作list或dict来对集合赋值。还有一个
__delitem__()方法,用于删除某个元素。__getattr__(),用于处理对象没有的属性或方法:class Test(object):def __init__(self, name):self.name = namedef __getattr__(self, attr):print 'Test doesn\'t have attribute: %s' % attrtest = Test('aa')test.age # Test doesn't have attribute: age同样也可以返回方法。
只有在没有找到属性的情况下,才调用
__getattr__。__call__()使得实例本身可以称为一个函数。class Student(object):def __init__(self, name):self.name = namedef __call__(self, age):self.age = ageprint('My name is %s and my age is %s' % self.name, age)student = Student('Jackie')student(25) # My name is Jackie and my age is 25可以用
callbale()来判断一个对象是否能被调用。
元类
type()不仅可以用来查看某个对象的类型,也可以用来创建新的类:def fn(self, name='world'): # 先定义函数print('Hello, %s.' % name)Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello classh = Hello()h.hello() # Hello, world.print(type(Hello)) # <type 'type'>print(type(h)) # <class '__main__.Hello'>传入三个参数:
- 类名
- 继承的父类的tuple
- 属性和方法的dict
通过
type()函数创建的类和直接写class是完全一样的metaclass元类,暂时不学
错误、调试和测试
错误处理
try...except...finally...
|
except还会捕获异常的子类,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。
|
logging
Python内置的logging模块可以非常容易地记录错误信息。
|
|
自己编写错误
|
继续向上抛出异常
|
调试
断言assert
|
assert语句本身会抛出异常,AssertionError
可以用-O参数关闭assert:python -O err.py
日志logging
几个级别:debug,info,warning,error。
可以指定级别,当我们指定level=INFO时,logging.debug就不起作用了。
|
单元测试
unittest模块
|
测试类:从
unittest.TestCase继承。以
test开头的方法才会被认为是测试方法,才能被执行用断言来判断是否符合期望,
assertEquals()assertTrue(),以及抛出异常:with self.assertRaises(AttributeError):value = d.empty
运行单元测试
在单元测试文件
mydict_test.py下加上两行代码:if __name__ == '__main__':unittest.main()这样就可以像正常脚本一样运行了
$ python mydict_test.py用参数
-m unittest:$ python -m unittest mydict_test.py
setUp()和tearDown()
分别会在每调用一个测试方法的前后分别被执行。
文档测试
doctest模块:
|
运行测试:python mydict.py
IO编程
文件读写
|
由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。最好用try...finally来写:
|
Python引入了with语句来帮助调用:
|
read(size)可以读取 size个字节的内容readline()可以读取一行内容readlines()一次读取所有内容并按行返回list
操作文件和目录
os模块
|
os模块不提供拷贝文件的接口,而shutil模块提供了copyfile()的函数。
序列化(pickling)
序列化:把变量从内存中变成可存储或传输的过程。
cPickle和pickle
|
|
JSON
内置的json模块
|
定制JSON序列化
将某个class的实例序列化成JSON:
|
- 偷懒的方法:利用
__dict__属性,它就是一个dict,用来存储实例变量。
反序列化:
|
进程和线程
多进程(multiprocessing)
Unix/Linux操作系统提供了一个fork()系统调用,子进程永远返回0,而父进程返回子进程的ID。子进程只需要调用getppid()就可以拿到父进程的ID。
|
multiprocessing模块 - 跨平台
|
|
Pool 进程池
|
Pool默认大小是CPU核数,当创建多于Pool大小的进程数时,后面的进程就会等待前面的进程执行完成再执行。
|
也可以设置p = Pool(5)同时运行5个进程。
进程间通讯
Queue策略
|
还有Pipes等策略
多线程
threading高级模块对thread模块进行了封装,较常使用。
|
|
Lock
|
多核CPU
Python因为存在global interpret lock(GIL锁)的关系,虽然可以多线程执行,但无法真正利用多核。每个进程最多利用2两个核。
ThreadLocal
为每个线程单独建立作用域
|