练习: 规范化这段代码
from django.conf import settings
from user.models import *
import sys, os
mod=0xffffffff
def foo ( a , b = 123 ):
c={ 'x' : 111 , 'y' : 222 }#定义一个字典
d=[ 1 , 3,5 ]
return a,b , c
def bar(x):
if x%2==0 : return True
为什么要有编码规范
代码编排:
import
from xxx import *
空格
: ,
后面跟一个空格, 前面无空格 (行尾分号后无空格)+ - * / // = & |
== != > < >= <= is not in
and or not
& | ^ << >>
=
用于指示关键字参数或默认参数值时, 不要在其两侧使用空格适当添加空行
注释
docstring
命名
Error
或 Wraning
后缀语意明确、直白
not xx in yy
VS xx not in yy
not a is b
VS a is not b
程序的构建
自定义的变量名、函数名不要与标准库中的名字冲突
pip install pycodestyle pylint flake8 autopep8
函数定义时接收不定长参数
def foo(*args, **kwargs):
pass
参数传递
def foo(x, y,z, a, b):
print(x)
print(y)
print(z)
print(a)
print(b)
lst = [1, 2, 3]
dic = {'a': 22, 'b': 77}
foo(*lst, **dic)
import * 语法
文件 xyz.py
__all__ = ('a', 'e', '_d')
a = 123
_b = 456
c = 'asdfghjkl'
_d = [1,2,3,4,5,6]
e = (9,8,7,6,5,4)
文件 abc.py
from xyz import *
print(a)
print(_b)
print(c)
print(_d)
print(e)
==, is
: ==
判断的是值, is
判断的是内存地址 (即对象的id)
小整数对象: [-5, 256]
copy, deepcopy
的区别
copy
: 只拷贝表层元素deepcopy
: 在内存中重新创建所有子元素练习1: 说出执行结果
def extendList(val, lst=[]):
lst.append(val)
return lst
list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')
练习2: 说出下面执行结果
from copy import copy, deepcopy
from pickle import dumps, loads
a = ['x', 'y', 'z']
b = [a] * 3 # [['x','y','z'], ['x','y','z'], ['x','y','z']]
c = copy(b)
d = deepcopy(b)
e = loads(dumps(b, 4))
b[1].append(999)
b.append(777)
c[1].append(999)
c.append(555)
d[1].append(999)
d.append(333)
e[1].append(999)
e.append(111)
自定义 deepcopy: my_deepcopy = lambda item: loads(dumps(item, 4))
练习: 说出如下代码的打印结果
>>> def foo():
... print(111)
... yield 222
... print(333)
... yield 444
... print(555)
>>> n = foo()
>>> next(n)
>>> next(n)
>>> next(n)
generator: 生成器是一种特殊的迭代器, 不需要自定义 __iter__
和 __next__
class Range:
def __init__(self, start, end=None, step=1):
if end is None:
self.end = start
self.start = 0
else:
self.start = start
self.end = end
self.step = step
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
current = self.start
self.start += self.step
return current
else:
raise StopIteration()
iterator: 任何实现了 __iter__
和 __next__
方法的对象都是迭代器.
__iter__
得到一个迭代器。迭代器的__iter__()
返回自身__next__
返回迭代器下一个值__next__()
, 而是 next()
str / bytes / list / tuple / dict / set
自身不是迭代器,他们自身不具备 __next__()
, 但是具有 __iter__()
, __iter__()
方法用来把自身转换成一个迭代器
练习1: 定义一个随机数迭代器, 随机范围为 [1, 50], 最大迭代次数 30
import random
class RandomIter:
def __init__(self, start, end, times):
self.start = start
self.end = end
self.count = times
def __iter__(self):
return self
def __next__(self):
self.count -= 1
if self.count >= 0:
return random.randint(self.start, self.end)
else:
raise StopIteration()
练习2: 自定义一个迭代器, 实现斐波那契数列
class Fib:
def __init__(self, max_value):
self.prev = 0
self.curr = 1
self.max_value = max_value
def __iter__(self):
return self
def __next__(self):
if self.curr <= self.max_value:
res = self.curr
self.prev, self.curr = self.curr, self.prev + self.curr # 为下一次做准备
return res
else:
raise StopIteration()
练习3: 自定义一个生成器函数, 实现斐波那契数列
def fib(max_value):
prev = 0
curr = 1
while curr < max_value:
yield curr
prev, curr = curr, curr + prev
迭代器、生成器有什么好处?
各种推导式
[i * 3 for i in range(5) if i % 2 == 0]
{i: i + 3 for i in range(5)}
{i for i in range(5)}
最简装饰器
from functools import wraps
def deco_outter(n):
def deco(func):
@wraps(func)
def wrap(*args, **kwargs):
return func(*args, **kwargs)
return wrap
return deco
@deco(10)
def foo(a, b):
return a ** b
原理
对比被装饰前后的 foo.__name__
和 foo.__doc__
from functools import wraps
def deco(func):
'''i am deco'''
@wraps(func) # 还原被装饰器修改的原函数属性
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap
简单过程
fn = deco(func)
foo = fn
foo(*args, **kwargs)
多个装饰器叠加调用的过程
@deco1
@deco2
@deco3
def foo(x, y):
return x ** y
# 过程拆解 1
fn3 = deco3(foo)
fn2 = deco2(fn3)
fn1 = deco1(fn2)
foo = fn1
foo(3, 4)
# 过程拆解 2
# 单行: deco1( deco2( deco3(foo) ) )(3, 2)
deco1(
deco2(
deco3(foo)
)
)(3, 4)
带参数的装饰器
def deco(n):
def wrap1(func):
def wrap2(*args, **kwargs):
return func(*args, **kwargs)
return wrap2
return wrap1
# 调用过程
wrap1 = deco(n)
wrap2 = wrap1(foo)
foo = wrap2
foo()
# 单行形式
check_result(30)(foo)(4, 8)
装饰器类和 __call__
class Deco:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
@Deco
def foo(x, y):
return x ** y
# 过程拆解
fn = Deco(foo)
foo = fn
foo(12, 34)
使用场景
练习1: 写一个 timer 装饰器, 计算出被装饰函数调用一次花多长时间, 并把时间打印出来
import time
from functools import wraps
def timer(func):
@wraps(func) # 修正 docstring
def wrap(*args, **kwargs):
time0 = time.time()
result = func(*args, **kwargs)
time1 = time.time()
print(time1 - time0)
return result
return wrap
练习2: 写一个 Retry 装饰器
import time
class retry(object):
def __init__(self, max_retries=3, wait=0, exceptions=(Exception,)):
self.max_retries = max_retries
self.exceptions = exceptions
self.wait = wait
def __call__(self, func):
def wrapper(*args, **kwargs):
for i in range(self.max_retries + 1):
try:
result = func(*args, **kwargs)
except self.exceptions:
time.sleep(self.wait)
continue
else:
return result
return wrapper
Function Closure: 引用了自由变量的函数即是一个闭包. 这个被引用的自由变量和这个函数一同存在, 即使已经离开了创造它的环境也不例外.
说出下面函数返回值
def foo():
l = []
def bar(i):
l.append(i)
return l
return bar
f1 = foo()
f2 = foo()
# 说出下列语句执行结果
f1(1)
f1(2)
f2(3)
深入一点: object.__closure__
作用域
┌───────────────────────────┐
│ built-in namespace │
├───────────────────────────┤ ↑
│ global namespace │
│ ┌───────────────────────┤
│ │ local namespace │ n = 123
│ │ ┌───────────────────┤
│ │ │ local namespace │ ↑
│ │ │ ┌───────────────┤
│ │ │ │ ... │ print(n)
└───┴───┴───┴───────────────┘
global
nonlocal
globals()
locals()
vars([object]) # 不传参数相当于 locals(), 传入对象后, 会得到 object.__dict__
method
classmethod
staticmethod
练习: 说出下面代码的运行结果
class Test(object):
x = 123
def __init__(self):
self.y = 456
def bar1(self):
print('i am a method')
@classmethod
def bar2(cls):
print('i am a classmethod')
@staticmethod
def bar3():
print('i am a staticmethod')
def foo1(self):
print(self.x)
print(self.y)
self.bar1()
self.bar2()
self.bar3()
@classmethod
def foo2(cls):
print(cls.x)
print(cls.y) # 会报错
cls.bar1() # 会报错,因为bar1是实例方法. 得通过self.bar1
cls.bar2()
cls.bar3()
@staticmethod
def foo3(obj):
print(obj.x)
print(obj.y)
obj.bar1()
obj.bar2()
obj.bar3()
t = Test()
t.foo1()
t.foo2()
t.foo3()
什么是多态
class Animal:
def run(self):
print('animal running')
class Lion(Animal):
def run(self):
print('lion running')
class Tiger(Animal):
def run(self):
print('tiger running')
class LionTiger(Lion, Tiger):
pass
cub = LionTiger()
cub.run()
isinstance(cub, Lion)
isinstance(cub, Tiger)
多继承
方法和属性的继承顺序: Cls.mro()
菱形继承问题
继承关系示意
菱形继承
A.foo()
/ \
B C.foo()
\ /
D.mro() # 方法的继承顺序,由 C3 算法得到
Mixin: 通过单纯的 mixin 类完成功能组合
super
class A:
def __init__(self):
print('enter A')
self.x = 111
print('exit A')
class B(A):
def __init__(self):
print('enter B')
self.y = 222
A.__init__(self)
# super().__init__()
print('exit B')
class C(A):
def __init__(self):
print('enter C')
self.z = 333
A.__init__(self)
# super().__init__()
print('exit C')
class D(B, C):
def __init__(self):
print('enter D')
B.__init__(self)
C.__init__(self)
# super().__init__()
print('exit D')
d = D()
Garbage Collection (GC)
引用计数
优点: 简单、实时性高
==>
缺点: 消耗资源、循环引用
lst1 = [3, 4] # lst1->ref_count 1
lst2 = [8, 9] # lst2->ref_count 1
# lst1 -> [3, 4, lst2]
lst1.append(lst2) # lst2->ref_count 2
# lst2 -> [8, 9, lst1]
lst2.append(lst1) # lst1->ref_count 2
del lst1 # lst1->ref_count 1
del lst2 # lst2->ref_count 1
标记-清除, 分代收集
__str__
格式化输出对象
__init__
和 __new__
__new__
创建一个实例,并返回类的实例
__init__
初始化实例,无返回值
__new__
是一个特殊的类方法,不需要使用@classmethod来装饰.
class A(object):
'''单例模式'''
obj = None
def __new__(cls, *args, **kwargs):
if cls.obj is None:
cls.obj = object.__new__(cls)
return cls.obj
数学运算、比较运算
运算符重载
+
: __add__(value)
-
: __sub__(value)
substract*
: __mul__(value)
mulply/
: __truediv__(value)
(Python 3.x), __div__(value)
(Python 2.x) divide//
: __floordiv__(value)
%
: __mod__(value)
&
: __and__(value)
|
: __or__(value)
练习: 实现字典的 __add__
方法, 作用相当于 d.update(other)
class Dict(dict):
def __add__(self, other):
if isinstance(other, dict):
new_dict = {}
new_dict.update(self)
new_dict.update(other)
return new_dict
else:
raise TypeError('not a dict')
比较运算符的重载
==
: __eq__(value)
!=
: __ne__(value)
>
: __gt__(value)
>=
: __ge__(value)
<
: __lt__(value)
<=
: __le__(value)
练习: 完成一个类, 实现数学上无穷大的概念
class Inf:
def __lt__(self, other):
return False
def __le__(self, other):
return False
def __ge__(self, other):
return True
def __gt__(self, other):
return True
def __eq__(self, other):
return False
def __ne__(self, other):
return True
容器方法
__len__
-> len
__iter__
-> for
__contains__
-> in
__getitem__
对 string, bytes, list, tuple, dict
有效
__setitem__
对 list, dict
有效
__missing__
对 dict 有效, 字典的预留接口, dict 本身并没有实现
class Dict(dict):
def __missing__(self, key):
self[key] = None # 当检查到 Key 缺失时, 可以做任何默认行为
可执行对象: __call__
上下文管理 with:
__enter__
进入 with
代码块前的准备操作__exit__
退出时的善后操作class A:
def __enter__(self):
return self
def __exit__(self, Error, error, traceback):
print(Error, error, traceback)
__setattr__, __getattribute__, __getattr__, __dict__
内建函数:setattr(), getattr(), hasattr()
python的内省.
常用来做属性监听
class User:
'''TestClass'''
z = [7,8,9]
def __init__(self):
self.money = 10000
self.y = 'abc'
def __setattr__(self, name, value):
if name == 'money' and value < 0:
raise ValueError('money < 0')
print('set %s to %s' % (name, value))
object.__setattr__(self, name, value)
def __getattribute__(self, name):
print('get %s' % name)
return object.__getattribute__(self, name)
def __getattr__(self, name):
print('not has %s' % name)
return -1
def foo(self, x, y):
return x ** y
# 对比
a = User()
print(User.__dict__)
print(a.__dict__)
槽: __slots__
固定类所具有的属性
实例不会分配 __dict__
实例无法动态添加属性
优化内存分配, 大概能节约40%的内存.
class A:
__slots__ = ('x', 'y')
计算密集型
I/O 密集型 (input/output)
多任务处理
名称 | 资源占用 | 数据通信 | 上下文切换 (Context) |
---|---|---|---|
进程 | 大(M) | 不方便 (网络、共享内存、管道等) | 操作系统按时间片切换, 不够灵活, 慢 |
线程 | 小(k) | 非常方便 | 按时间片切换, 不够灵活, 快 |
协程 | 非常小(bytes) | 非常方便 | 根据I/O事件切换, 更加有效的利用 CPU |
全局解释器锁 ( GIL )
什么是同步、异步、阻塞、非阻塞?
事件驱动 + 多路复用
协程:Stackless / greenlets / gevent | tornado / asyncio
import asyncio
async def foo(n):
for i in range(10):
print('wait %s s' % n)
await asyncio.sleep(n)
return i
task1 = foo(1)
task2 = foo(1.5)
tasks = [asyncio.ensure_future(task1),
asyncio.ensure_future(task2)]
loop = asyncio.get_event_loop() # 事件循环,协程调度器
loop.run_until_complete( asyncio.wait(tasks))
线程安全, 锁
格式化打印 json
json.dumps(data, indent=4, sort_keys=True, ensure_ascii=False)
json.dumps(data, ensure_ascii=False, separators=[',',':'])
确保能取到有效值
d.get(k, default)
无值时使用默认值,对原字典无修改d.setdefault
无值时使用默认值,并将默认值写入原字典x = a if foo() else b
a or b
python中所有的对象都有真值, or返回真的, and是遇到假的就返回.try…except… 的滥用
try...except
要指明具体错误, try
结构不是用来隐藏错误的, 而是用来有方向的处理错误的利用 dict 做模式匹配
def do1():
print('i am do1')
def do2():
print('i am do2')
def do3():
print('i am do3')
def do4():
print('i am do4')
mapping = {1: do1, 2: do2, 3: do3, 4: do4}
mod = random.randint(1, 10)
func = mapping.get(mod, do4)
func()
inf, -inf, nan
字符串拼接尽量使用 join
方式: 速度快, 内存消耗小
property: 把一个方法属性化
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
# c.x = xx user.password
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
else 子句: if, for, while, try
collections 模块
defaultdict
OrderedDict
Counter
c[n] += 1
namedtuple
Dog = namedtuple(‘Dog’, [‘head’, ‘body’, ‘leg’, ‘tail’])
dog = Dog(1,1,4,1)
dog.head