装饰器
一切皆对象
def hi():
pass
# 我们甚⾄可以将⼀个函数赋值给⼀个变量,⽐如
greet = hi
# 删除函数
del hi
def
当你把⼀对⼩括号放在后⾯,这个函数就会执⾏;
然⽽如果你不放括号在它后⾯,那它可以被到处传递,并且可以赋值给别的变量⽽不去执
⾏它。
蓝本规范:
from
@decorator_name
def func():
return("Function is running")
@wraps接受⼀个函数来进⾏装饰,并加⼊了复制函数名称、注释⽂档、参数列表
等等的功能。这可以让我们在装饰器⾥⾯访问在装饰之前的函数的属性。
授权 Authorization
装饰器能有助于检查某个⼈是否被授权去使⽤⼀个web应⽤的端点(endpoint)。它们被⼤量
使⽤于Flask和Django web框架中。这⾥是⼀个例⼦来使⽤基于装饰器的授权:
from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
多个return值
def profile():
name = "Danny"
age = 30
return name, age
这是一种比列表和字典更好的方式。不要使用global关键字,除非你知道你在做什么。
对象变动 Mutation
在Python中当函数被定义时,默认参数只会运算一次,而不是每次被调用时都会重新运算。
你应该永远不要定义可变类型的默认参数,除非你知道你正在做什么。你应该这样做:
def add_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
__slots__魔法
默认情况下Python用一个字典来保存一个对象的实例属性。这非常有用,因为它允许我们在运行时去设置任意的新属性。
为了节省内存,可以使用__slots__来告诉Python不要使用字典,而且只给一个固定集合的属性分配空间。使用__slots__之后,不可以设置__slots__之外的新属性。
class MyClass(object):
__slots__ = ['name', 'indentifier']
def __init__(self, name, indentifier):
self.name = name
self.identifier = identifier
# self.set_up() ...
测试内存使用 ipython_memory_usage(使用方法待研究)
virtualenv
virtualenv创建独立(隔离)的Python环境
安装:
pip install virtualenv
创建环境
virtualenv myproject
激活
cd myproject
source bin/activate
福利
你可以使⽤smartcd来帮助你管理你的环境,当你切换⽬录时,它可以帮助你激活
(activate)和退出(deactivate)你的virtualenv。我已经⽤了很多次,很喜欢它。
容器 Collections
defualtdict
defaultdict与dict类型不同,你不需要检查key是否存在。
from collections import defaultdict
另一个重要的例子是:当你在一个字典中对一个键进行嵌套赋值时,如果键不存在,会触发keyError异常。defaultdict允许我们用一个聪明的方式绕过这个问题。
问题:
some_dict = {}
some_dict['colours']['favourite'] = "yellow"
## 异常输出:KeyError: 'colours'
解决方案:
import collections
tree = lambda: collections.defaultdict(tree)
some_dict = tree()
some_dict['colours']['favourite'] = "yellow"
## 运行正常
import json
print(json.dumps(some_dict))
## output: {"colours": {"favourite": "yellow"}}
deque
deque提供了一个双端队列,你可以从头/尾两端添加或删除元素。
from colections import deque
namedtuple
你可以像字典一样访问namedtuple,但namedtuple是不可以变的。
from collection import namedtuple
Animal = namedtuple("Animal", "name age type")
perry = Animal(name="perry", age=31, type="cat")
print(perry.name)
namedtuple比字典快
你可以将命名元组转换为字典,方法如下:
print(perry._asdict())
# output OrderDict([("name", "Perry"), ("age", 31),...])
enum.Enum (Python 3.4+)
perry命名元组中type使用了字符串,容易写错,可以使用Enum规范一下,避免使用字符串。
from enum import Enum
class Species(Enum):
cat = 1
dog =2
horse = 3
上面的perry可以改写如下:
# old
# perry = Animal(name="perry", age=31, type="cat")
# new
perry = Animal(name="perry", age=31, type=Species.cat)
对象自省
inspect模块
inspect模块提供了许多有用的函数,来获取活跃对象的信息。
比如说查看一个对象的成员,只需运行:
import inspect
print(inspect.getmembers(str))
推导式
list comprehensions
规范
variable = [out_exp for out_exp in input_list if out_exp ==2]
例子:
mulitiples = [i for i in range(30) if i % 3 is 0]
dict comprehensions
快速对换字典的键和值
{v: k, for k, v in some_dict.items() }
set comprehensions
集合推导式跟列表推导式类似,唯一的区别在于它们使用大括号{}。
squared = {x**2 for x in [1,1,2]}
一行式
计算器:
python3 -c "print(100*200)"
# output 20000
列表展平 itertools.chain.from_iteerable
import itertools
print(list(itertools.chain.from_iteerable(a_list)))
# or
print(list(itertools.chain(*a_list)))
For - Else
for 后面的else会在循环结束时执行,这意思着,循环没有遇到任何break.
for item in container:
if search_something(item):
# Found it
process(item)
break
else:
# Didn't find anything...
not_found_in_container()