基础

dict

python内置了字典:dict的支持,dict全程dictionart,在其他语言种也成为map,使用键值对存储,具有极快的查找速度。

dict = {'name':'liu', age: 23}
print dict['name']

设置value

dict['name'] = 'junhui'

获取vaue

# 1,通过属性获取
dict['name']
# 如果key不存在,dict就会报错
# 避免错误需要通过in判断key是否存在
'name' in dict
dict['name']
# 2,通过get获取
dict.get('name')
# 如果key不存在,可以返回None,或者返回指定的value
dict.get('name', -1)

删除key-value

# 用pop(key)方法
dict.pop('name')

dict的特点

  1. 查找和插入速度极快

  2. 需要占用大量内存,内存浪费多

Set

同java和js种的set

语法

s = set([1,2,3])
# 增加
s.add(4)
# 删除
s.remove(4)

数据转换

int('123')
# 123
int(12.34)
# 12
float('12.34')
# 12.34
str(1.23)
# '1.23'
unicode(100)
# u'100'
bool(1)
# True
bool('')
# False
# 函数名赋值,同js
a = abs

函数

在python中,定义一个函数要使用def语句,一次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。

def my_bas(x):
if x >= 0:
return x
else:
return -x

空函数

如果需要定义一个空函数,可以用pass语句:

def nop():
pass

pass作为占位符,可以放在if中,while中作为主体

参数检查

调用函数时,如果参数个数不对,python会抛出TypeError异常

返回多个值

python的返回多个值,其实返回的仍然是单一值,返回的是tuple类型的值

def move(x, y):
return x, y
x, y = move(1, 2)
print x, y
# 1, 2
# or
r = move(1, 2)
print r
# (1, 2)

参数默认值

def power(x, y=2):
return x, y
print power(1, 2)
# (1, 2)

可变参数

def calc(*numbers):
sum = 0
for number in numbers:
sum = sum + number
return sum
# 如果传入的是数据,变成js中的解构写法
list = [1,2,3,4]
calc(*list)

切片

常用来取list中的部分元素。等于js中的split

list = [1,2,3,4,5,6,7,8]
list[0:3]
# [1,2,3]
# 如果第一个索引是0,可以省略
list[:3]
#[1,2,3]
# 支持倒数切片
list[-2:-1]
# [7,8]
list[-3:]
#[6,7,8]
# 可以用来复制数组
list[:]
#[1,2,3,4,5,6,7,8]
# tuple也可以用切片操作,只是切片返回的值也为tuple
tu = (1,2,3,4,5)
tu[:3]
#(1,2,3)
# 字符串也可以用切片操作
'qwerty'[:3]
#'qwe'

生成器

概念同js中的生成器(Generator),同java中的迭代器(Iterator)

# 创建一个生成器
list = [x * x for x in range(10)]
g = (x * x for x in range(10))
#使用生成器
g.next()
# 遍历生成器
for n in g:
print n

匿名函数

map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
# lambda x: x * x等于
def f(x):
return x * x

装饰器

同js中的装饰器,同java的注解

模块

#!/usr/bin/env python
# -*- coding: utf-8 -*-
' a test module '
__author__ = 'Michael Liao'
import sys
def test():
args = sys.argv
if len(args)==1:
print 'Hello, world!'
elif len(args)==2:
print 'Hello, %s!' % args[1]
else:
print 'Too many arguments!'
if __name__=='__main__':
test()

第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;

第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。

后面开始就是真正的代码部分。

import sys

导入sys模块后,我们就有了变量sys指向该模块,利用sys这个变量,就可以访问sys模块的所有功能。

sys模块有一个argv变量,用list存储了命令行的所有参数。argv至少有一个元素,因为第一个参数永远是该.py文件的名称,例如:

运行python hello.py获得的sys.argv就是['hello.py']

运行python hello.py Michael获得的sys.argv就是['hello.py', 'Michael]

最后,注意到这两行代码:

if __name__=='__main__':
test()

当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

作用域

模块内部使用的私有变量,通过_前缀来实现

类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author____name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

安装第三方模块

在python中,安装第三方模块,是通过setuotools这个工具完成的。官方推荐pip

pip install xxx

使用_future\_

python版本迭代会有不兼容的api,所以python提供了__future__模块,把下一个新版本的特性导入到当前版本

from __future__ import unicode_literals

面向对象

class Per(object):
def __init__(self, name):
self.name = name
def print_name(self):
print self.name

__init__方法可以理解为js和java中的构造函数。

方法中的第一个参数永远是self,表示创建的示例本身,等同于js中的this指针。同时调用方法时,self不需要传递,python解释器自己会把示例传进去。

per = Per('liu')
per.print_name()
# 'liu'

继承和多态

# 继承
class Animal(object):
def run(self):
print 'run'
class Dog(Animal):
pass
class Cat(Animal):
pass

获取对象信息

type()

# type()可以理解为js中的typeof
type(123)
# <type 'int'>
type(None)
# <type 'NoneType'>
a = Animal()
type(a)
# <class '__main__.Animal'>

isinstance()

isinstance可以通过查找继承关系来确定类型

# 继承关系object -> Animal -> Dog
a = Animal()
d = Dog()
isinstance(d, Dog)
# True
isinstance(d, Animal)
# True

dir()

dir可以用来获取一个对象所有的属性和方法,它返回一个包含字符串的list

dir('ABC')
#['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度。在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法,所以,下面的代码是等价的:

len('ABC')
# 3
'ABC'.__len__()
# 3

我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法:

class MyObject(object):
def __len__(self):
return 100
pass
obj = MyObject()
len(obj)
# 100

get&set&hasattr

getattr&setattr是用来获取和设置对象的属性的api。hasattr等同于hasOwnProperty

class MyObject(object):
def __init(self, x):
self.x = x
pass
pass
obj = MyObject(1)
hasattr(obj, 'x')
# True
getattr(obj, 'y')
# <bound method MyObject.y of <__main__.MyObject object at 0x108ca35d0>>
setattr(obj, 'y', 12)

__slots__

动态给对象增加方法

obj = MyObject(1)
# 单个实例增加方法或属性
#1.定义一个方法
def print_x(self):
print self.x
# 引用MethodType
from types import MethodType
obj.print_x = MethodType(print_x, obj, MyObject)
obj.print_x()
# 1
# 给所有实例绑定方法
def set_y(self, y):
self.y = y
MyObject.set_y = MethodType(set_y, None, MyObject)

使用_slots\_来限制class的属性,比如只允许对MyObject实例添加yz属性。为了达到限制的目的,python允许再定义class的时候,定义一个特殊的__slots__变量,来限制改class能添加的属性。

class MyObject(object):
__slots__ = ('y', 'z')# 用tuple定义允许绑定的属性名称

注意:__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的。

使用@property

@property用途等同于js对象中的getter&setter

class MyObject(object):
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value

定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:

class MyObject(object):
@property
def r(self):
return self._r

多重继承

class Animal(object):
pass
# 大类:
class Mammal(Animal):
pass
class Bird(Animal):
pass
class Runnable(object):
def run(self):
print('Running...')
class Flyable(object):
def fly(self):
print('Flying...')
# 各种动物:
class Dog(Mammal, Runnable):
pass

Mixin

在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为Mixin。

自定义类

特殊函数,类似于java中对象的toString()hashCode()compareTo()等,python中也可以对class的类似函数进行重写。

_str_

class MyObject(object):
def __init__(self, x);
self.x = x
def __str__(self):
return self.x
print MyObject(2)
# 2

__str__是用来是返回对象实例的字符串,如果直接在控制台输出实例对象,则需要重写__repr__方法,__repr__是为调试服务的。

_iter_

class的迭代器方法,该方法返回一个迭代对象(iterator),如果重写此方法,则表示此class可以被迭代。

class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __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 # 返回下一个值

_getitem_

重写该方法,可以用来获取类似于数组下标的元素

class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
f = Fib()
f[0]
# 1
f[1]
# 1

list的切片,用__getitem__依然可以做到,重写__getitem__,判断传入的是int或者slice

class Fib(object):
def __getitem__(self, n):
if isinstance(n, int):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice):
start = n.start
stop = n.stop
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
f = Fib()
f[0:5]
# [1, 1, 2, 3, 5]

_setitem_

把对象视作list或dict来对集合赋值。

_delitem_

用于删除某个元素。

_getattr_

在python中,可以使用__getattr__方法,来动态获取属性。

class MyObject(object):
def __init__(self, x):
self.x = x
def __getattr__(self, attr):
if attr== 'y':
return 1
obj = MyObject(2)
obj.y
# 1

注意:只有在没找到属性得情况下,才调用__getattr__,已有得属性,不会在__getattr__中查找

_call_

实现__call__方法,可以直接对实例进行调用。

class MyObject(object):
def __call__(self):
print 'call'
obj = MyObject()
obj()
# call

使用元类

type()

使用type()可以动态创建class,无需使用class关键字创建class

def fn(self, name='world'):
print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn))
h = Hello()
h.hello()
# Hello, world.

type()需要传递三个参数:

  1. class得名称。

  2. 继承得父类集合,python支持多继承,需要使用tuple来传递。

  3. class得方法名称与函数绑定

mateclass

mateclass用来创建类,然后使用类来创建实例对象,可以理解为类的蓝本。

mateclass允许创建类或者修改类,类就是mateclass的实例对象。

# metaclass是创建类,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list):
__metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类

当创建MyList实例时,要通过ListMetaclass.__new__()来创建,在此,可以修改类的定义

__new__方法接收到的参数依次是:

  1. 当前准备创建的类的对象;

  2. 类的名字;

  3. 类继承的父类集合;

  4. 类的方法集合。

错误、调试、测试

error处理

try:
print 'try...'
r = 10 / 0
print 'result:', r
except ZeroDivisionError, e:
print 'except:', e
finally:
print 'finally...'
print 'END'

debug

python中可以使用assert来断言调试

# err.py
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')

assert的意思是,表达式n != 0应该是True,否则,后面的代码就会出错。

如果断言失败,assert语句本身就会抛出AssertionError

$ python err.py
Traceback (most recent call last):
...
AssertionError: n is zero!

启动python解释器时可以使用-O参数来关闭assert

$ python -O err.py
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero

关闭后,你可以把所有的assert语句当成pass来看。

logging

python的日志记录

pdb

python的调试器.

单元测试

pass

IO编程

文件读写

# r标识符表示读
f = open('./test.txt', 'r')
f.read()
# 'Hello, world!'
f.close()

可以用with关键字对try except finally语句进行优化

with open('file_name','r') as f:
r=f.read()

f = open('./test.txt', 'w')

进程和线程

python的os模块封装了常见的系统调用,包含fork可以在python程序中创建子进程.

import os
print `Process (%s) start...` % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
# Process (876) start...
# I (876) just created a child process (877).
# I am child process (877) and my parent is 876.

由于windows没有fork调用,所以上面的代码无法在windows中运行

multiptocessing

multiprocessing模块是跨平台版本的多进程模块.

multiprocessing模块提供了一个Process类来代表一个进程对象.

from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print 'Run child process %s (%s)...' % (name, os.getpid())
if __name__ == '__mainA__':
print 'Parent process %s.' % os.getpid()
p = Process(target = run_proc, args=('test',))
print 'Process will start.'
p.start()
p.join()
print 'Process end.'
# Parent process 928.
# Process will start.
# Run child process test (929)...
# Process end.

创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()`方法启动.

join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步.

Pool

如果要穷的那个大量的子进程,可以用进程池的方式批量创建子进程.

from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print 'Run task%s (%s)...' %(name,os.getpid())
start = time.time()
time.sleep(random.random()*3)
end = time.time()
print 'Task %s runs %0.2f seconds.' % (name,(end - start))
if __name__ == '__main__':
print 'Parent process %s.' % os.getpid()
p = Pool()
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print 'Waiting for all subprocess done...'
p.close()
p.join()
print 'All subprocess done.'
Parent process 669.
Waiting for all subprocesses done...
Run task 0 (671)...
Run task 1 (672)...
Run task 2 (673)...
Run task 3 (674)...
Task 2 runs 0.14 seconds.
Run task 4 (673)...
Task 1 runs 0.27 seconds.
Task 3 runs 0.86 seconds.
Task 0 runs 1.41 seconds.
Task 4 runs 1.91 seconds.
All subprocesses done.

Pool对象调用join()方法会等待所有子进程执行外币,调用join()之前必须先调用close()调用close()之后就不能继续添加新的Process了.

进程间通信

Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信.Python的mulitiprocess模块包装了底层的机制,提供了Queue,Pipes等多种方式来交换数据. Queue:

from multiprocess import Process, Queue
import os, time, random
# 写数据进程执行的代码
def write(q):

多线程

python标准库提供了两个模块:thread&threading,thread是低级模块,threading是高级模块,对thread进行了封装.大多数情况下,仅使用threading高级模块.

import time, threading
# 新县城执行的代码
def loop():
print 'thread %s is running...' % threading.current_thread().name
n = 0
while n < 5:
n = n + 1
print 'thread %s >>> %s' % (threading.current_thread().name, n)
time.sleep(1)
print 'thread %s ended.' % threading.current_thread().name
print 'thread %s is running...' % threading.current_thread().name
t = threading.Thread(target = loop, name='LoopThread')
t.start()
t.join()
print 'thread %s ended.' % threading.current_thread().name

Lock

线程锁,等同于java中的lock

import threading
lock = threading.Lock()
# 获取锁:
lock.acquire()
# 解锁
lock.release()

Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核

ThreadLocal

线程内局部变量

import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
print 'Hello, %s (in %s)' % (local_school.student, threading.current_thread().name)
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
# Hello, Alice (in Thread-A)
# Hello, Bob (in Thread-B)

分布式进程

# taskmanager.py
import random, time, Queue
from multiprocessing.managers import BaseManager
# 发送任务的队列:
task_queue = Queue.Queue()
# 接收结果的队列:
result_queue = Queue.Queue()
# 从BaseManager继承的QueueManager:
class QueueManager(BaseManager):
pass
# 把两个Queue都注册到网络上, callable参数关联了Queue对象:
QueueManager.register('get_task_queue', callable=lambda: task_queue)
QueueManager.register('get_result_queue', callable=lambda: result_queue)
# 绑定端口5000, 设置验证码'abc':
manager = QueueManager(address=('', 5000), authkey='abc')
# 启动Queue:
manager.start()
# 获得通过网络访问的Queue对象:
task = manager.get_task_queue()
result = manager.get_result_queue()
# 放几个任务进去:
for i in range(10):
n = random.randint(0, 10000)
print('Put task %d...' % n)
task.put(n)
# 从result队列读取结果:
print('Try get results...')
for i in range(10):
r = result.get(timeout=10)
print('Result: %s' % r)
# 关闭:
manager.shutdown()
# taskworker.py
import time, sys, Queue
from multiprocessing.managers import BaseManager
# 创建类似的QueueManager:
class QueueManager(BaseManager):
pass
# 由于这个QueueManager只从网络上获取Queue,所以注册时只提供名字:
QueueManager.register('get_task_queue')
QueueManager.register('get_result_queue')
# 连接到服务器,也就是运行taskmanager.py的机器:
server_addr = '127.0.0.1'
print('Connect to server %s...' % server_addr)
# 端口和验证码注意保持与taskmanager.py设置的完全一致:
m = QueueManager(address=(server_addr, 5000), authkey='abc')
# 从网络连接:
m.connect()
# 获取Queue的对象:
task = m.get_task_queue()
result = m.get_result_queue()
# 从task队列取任务,并把结果写入result队列:
for i in range(10):
try:
n = task.get(timeout=1)
print('run task %d * %d...' % (n, n))
r = '%d * %d = %d' % (n, n, n*n)
time.sleep(1)
result.put(r)
except Queue.Empty:
print('task queue is empty.')
# 处理结束:
print('worker exit.')