1、Programmer tools
1.1 Virtual Environment
virtualenv是什么?
virtualenv是年迈pythoner的必备良品,主要用来做环境隔离。 比如说你维护的代码一个要求python2,一个要求python3, 一个要求django1.0,一个要求django2.0,要是使用系统的环境,就会不断的切版本,升降级,尤其是部署到集成环境时,可能会产生更为严重的冲突。
如何解决?
使用virtualenv!针对每个程序创建独立(隔离)的Python环境,而不是在全局安装所依赖的模块。
$ pip install virtualenv
$ virtualenv myproject
$ source myproject/bin/activate
$ deactivate
执行第一个命令在myproject文件夹创建一个隔离的virtualenv环境,第二个命令激活这个隔离的环境(virtualenv)。
如果你想让你的virtualenv使用系统全局模块,请使用–system-site-packages参数创建你的virtualenv,例如:
virtualenv --system-site-packages mycoolproject
1.2 Debugging
pdb是python调试用的库,但是我觉得还是IDE的debug模式方便些。
命令行
$ python -m pdb my_script.py
这会触发debugger在脚本第一行指令处停止执行。这在脚本很短时会很有帮助。你可以通过(Pdb)模式接着查看变量信息,并且逐行调试。
脚本内部运行
import pdb
def make_bread():
pdb.set_trace()
return "I don't have time"
print(make_bread())
命令列表:
- c: 继续执行
- w: 显示当前正在执行的代码行的上下文信息
- a: 打印当前函数的参数列表
- s: 执行当前代码行,并停在第一个能停的地方(相当于单步进入)
- n: 继续执行到当前函数的下一行,或者当前行直接返回(单步跳过)
单步跳过(next)和单步进入(step)的区别在于, 单步进入会进入当前行调用的函数内部并停在里面, 而单步跳过会(几乎)全速执行完当前行调用的函数,并停在当前函数的下一行。
1.3 对象自省(Object introspection)
自省(introspection),在计算机编程领域里,是指在运行时来判断一个对象的类型的能力。它是Python的强项之一。Python中所有一切都是一个对象,而且我们可以仔细勘察那些对象。
dir
它返回一个列表,列出了一个对象所拥有的属性和方法。这里是一个例子:
my_list = [1, 2, 3]
dir(my_list)
# Output: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
# '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
# '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__',
# '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
# '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
# '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__',
# '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop',
# 'remove', 'reverse', 'sort']
上面的自省给了我们一个列表对象的所有方法的名字。
如果我们运行dir()而不传入参数,那么它会返回当前作用域的所有名字。
type 和 id
type函数返回一个对象的类型。
print(type(''))
# Output: <type 'str'>
print(type([]))
# Output: <type 'list'>
print(type({}))
# Output: <type 'dict'>
print(type(dict))
# Output: <type 'type'>
print(type(3))
# Output: <type 'int'>
id()函数返回任意不同种类对象的唯一ID
name = "Yasoob"
print(id(name))
# Output: 139972439030304
inspect
inspect模块也提供了许多有用的函数,来获取活跃对象的信息。比方说,你可以查看一个对象的成员,只需运行
import inspect
print(inspect.getmembers(str))
# Output: [('__add__', <slot wrapper '__add__' of ... ...
2、语法
2.1 Exceptions
最基本的术语里我们知道了try/except从句。可能触发异常产生的代码会放到try语句块里,而处理异常的代码会在except语句块里实现。这是一个简单的例子:
try:
file = open('test.txt', 'rb')
except IOError as e:
print('An IOError occurred. {}'.format(e.args[-1]))
处理多个异常
第一种方法需要把所有可能发生的异常放到一个元组里。
try:
file = open('test.txt', 'rb')
except (IOError, EOFError) as e:
print("An error occurred. {}".format(e.args[-1]))
另外一种方式是对每个单独的异常在单独的except语句块中处理。我们想要多少个except语句块都可以。 如果异常没有被第一个except语句块处理,那么它也许被下一个语句块处理,或者根本不会被处理
try:
file = open('test.txt', 'rb')
except EOFError as e:
print("An EOF error occurred.")
raise e
except IOError as e:
print("An error occurred.")
raise e
最后一种方式会捕获所有异常
try:
file = open('test.txt', 'rb')
except Exception:
# 打印一些异常日志,如果你想要的话
raise
finally 从句
包裹到finally从句中的代码不管异常是否触发都将会被执行。这可以被用来在脚本执行之后做清理工作。
try:
file = open('test.txt', 'rb')
except IOError as e:
print('An IOError occurred. {}'.format(e.args[-1]))
finally:
print("This would be printed whether or not an exception occurred!")
# Output: An IOError occurred. No such file or directory
# This would be printed whether or not an exception occurred!
try/else 从句
else从句只会在没有异常的情况下执行,而且它会在finally语句之前执行。
try:
print('I am sure no exception is going to occur!')
except Exception:
print('exception')
else:
# 这里的代码只会在try语句里没有触发异常时运行,
# 但是这里的异常将 *不会* 被捕获
print('This would only run if no exception occurs. And an error here '
'would NOT be caught.')
finally:
print('This would be printed in every case.')
# Output: I am sure no exception is going to occur!
# This would only run if no exception occurs.
# This would be printed in every case.
2.2 For - Else
for循环有一个else从句,这个else从句会在循环正常结束时执行。这意味着,循环没有遇到任何break.
有个常见的构造是跑一个循环,并查找一个元素。如果这个元素被找到了,我们使用break来中断这个循环。有两个场景会让循环停下来。
- 第一个是当一个元素被找到,break被触发。
- 第二个场景是循环结束。 现在我们也许想知道其中哪一个,才是导致循环完成的原因。一个方法是先设置一个标记,然后在循环结束时打上标记。另一个是使用else从句。
比如说找质数,如果是正常for,需要在里面增加flag判断
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'equals', x, '*', n / x)
break
加入else,会简单很多
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'equals', x, '*', n / x)
break
else:
# loop fell through without finding a factor
print(n, 'is a prime number')
2.3 三元表达式
#如果条件为真,返回真 否则返回假
condition_is_true if condition else condition_is_false
还有一种比较晦涩的使用了元组的三元表达式,不常用。
#(返回假,返回真)[真或假]
(if_test_is_false, if_test_is_true)[test]
举个栗子:
fat = True
fitness = ("skinny", "fat")[fat]
print("Ali is", fitness)
#输出: Ali is fat
元组三元表达式会执行两个元组值后,再去判断真假;而if else 则if 条件为false时才会执行else语句。
2.4 Global & Return
global代替return:声明global变量。
def add(value1,value2):
global result
result = value1 + value2
add(3,5)
print(result)
# Output: 8
一般情况尽量避免使用global,会引入全局域,使语义变复杂。
一次返回多个值
返回一个包含多个值的tuple(元组),list(列表)或者dict(字典)
def profile():
name = "Danny"
age = 30
return (name, age)
profile_data = profile()
print(profile_data[0])
# Output: Danny
print(profile_data[1])
# Output: 30
# 更常见的方式:也是返回元组,只不过省略了括号
def profile():
name = "Danny"
age = 30
return name, age
2.5 open函数
with open('photo.jpg', 'r+') as f:
jpgdata = f.read()
open的第一个参数是文件名。第二个(mode 打开模式)决定了这个文件如何被打开。
- 如果你想读取文件,传入r
- 如果你想读取并写入文件,传入r+
- 如果你想覆盖写入文件,传入w
- 如果你想在文件末尾附加内容,传入a
- 二进制加 b
注意项:
- 是否有异常时的close处理:使用with open(‘photo.jpg’, ‘rb’) as inf:
- 注意编码,python2不支持编码,但是可以用io替代
with io.open('summary.txt', 'w', encoding='utf-8') as outf:
2.6 *args and **kwargs
*args 是用来发送一个非键值对的可变数量的参数列表给一个函数. **kwargs 允许你将不定长度的键值对, 作为参数传递给一个函数。
组合
# 首先使用 *args
>>> args = ("two", 3, 5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# 现在使用 **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
顺序
some_func(fargs, *args, **kwargs)
2.7 上下文管理器
上下文管理器允许你在有需要的时候,精确地分配和释放资源。 使用上下文管理器最广泛的案例就是with语句了。
with open('some_file', 'w') as opened_file:
opened_file.write('Hola!')
等价于
file = open('some_file', 'w')
try:
file.write('Hola!')
finally:
file.close()
基于类的实现
一个上下文管理器的类,最起码要定义__enter__和__exit__方法。
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
self.file_obj.close()
通过定义__enter__和__exit__方法,我们可以在with语句里使用它。我们来试试:
with File('demo.txt', 'w') as opened_file:
opened_file.write('Hola!')
__exit__函数接受三个参数:type, value和traceback。 当异常发生时,with语句会采取哪些步骤:
- 它把异常的type,value和traceback传递给__exit__方法
- 它让__exit__方法来处理异常
- 如果__exit__返回的是True,那么这个异常就被优雅地处理了。
- 如果__exit__返回的是True以外的任何东西,那么这个异常将被with语句抛出。
class File(object): def __init__(self, file_name, method): self.file_obj = open(file_name, method) def __enter__(self): return self.file_obj def __exit__(self, type, value, traceback): print("Exception has been handled") self.file_obj.close() return True with File('demo.txt', 'w') as opened_file: opened_file.undefined_function() # Output: Exception has been handled
__exit__方法返回了True,因此没有异常会被with语句抛出。
基于生成器的实现
还可以用装饰器和生成器来实现上下文管理器
from contextlib import contextmanager
@contextmanager
def open_file(name):
f = open(name, 'w')
yield f
f.close()
处理逻辑
1. Python解释器遇到了yield关键字。因为这个缘故它创建了一个生成器而不是一个普通的函数。
2. 因为这个装饰器,contextmanager会被调用并传入函数名(open_file)作为参数。
3. contextmanager函数返回一个以GeneratorContextManager对象封装过的生成器。
4. 这个GeneratorContextManager被赋值给open_file函数,我们实际上是在调用GeneratorContextManager对象。
使用
with open_file('some_file') as f:
f.write('hola!')
3、函数式编程
3.1 Enumerate
枚举(enumerate)是Python内置函数,可以在遍历数据时自动计数
for counter, value in enumerate(some_list):
print(counter, value)
可以指定开始值
my_list = ['apple', 'banana', 'grapes', 'pear']
for c, value in enumerate(my_list, 1):
print(c, value)
# 输出:
(1, 'apple')
(2, 'banana')
(3, 'grapes')
(4, 'pear')
3.2 Lambdas
lambda表达式是一行函数,也叫匿名函数。
lambda 参数:操作(参数)
add = lambda x, y: x + y
print(add(3, 5))
# Output: 8
# 列表排序
a = [(1, 2), (4, 1), (9, 10), (13, -3)]
a.sort(key=lambda x: x[1])
print(a)
# Output: [(13, -3), (4, 1), (1, 2), (9, 10)]
3.3 set数据结构
- 创建set
a_set = {'red', 'blue', 'green'} print(type(a_set)) ### 输出: <type 'set'>
- 去除重复项
some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n'] duplicates = set([x for x in some_list if some_list.count(x) > 1]) print(duplicates) ### 输出: set(['b', 'n'])
- 交集
valid = set(['yellow', 'red', 'blue', 'green', 'black']) input_set = set(['red', 'brown']) print(input_set.intersection(valid)) ### 输出: set(['red'])
- 差集
valid = set(['yellow', 'red', 'blue', 'green', 'black']) input_set = set(['red', 'brown']) print(input_set.difference(valid)) ### 输出: set(['brown'])
3.4 Map & Filter & reduce
map
Map会将一个函数映射到一个输入列表的所有元素上。
map(function_to_apply, list_of_inputs)
items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))
filter
filter过滤列表中的元素,并且返回一个由所有符合要求的元素所构成的列表,符合要求即函数映射到该元素时返回值为True。
number_list = range(-5, 5)
less_than_zero = filter(lambda x: x < 0, number_list)
print(list(less_than_zero))
# 译者注:上面print时,加了list转换,是为了python2/3的兼容性
# 在python2中filter直接返回列表,但在python3中返回迭代器
# 因此为了兼容python3, 需要list转换一下
# Output: [-5, -4, -3, -2, -1]
reduce
当需要对一个列表进行一些计算并返回结果时,可以使用Reduce。
from functools import reduce
product = reduce( (lambda x, y: x * y), [1, 2, 3, 4] )
# Output: 24
python3已经无法直接使用,需要额外引入
3.5 推导式
列表推导式
variable = [out_exp for out_exp in input_list if out_exp == 2]
字典推导式
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {
k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
for k in mcase.keys()
}
# mcase_frequency == {'a': 17, 'z': 3, 'b': 34}
#dict键值互换
{v: k for k, v in some_dict.items()}
集合推导式
squared = {x**2 for x in [1, 1, 2]}
print(squared)
# Output: {1, 4}
4、数据结构
4.1 生成器
可迭代对象(Iterable)
Python中任意的对象,只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法,那么它就是一个可迭代对象。
迭代器(Iterator)
任意对象,只要定义了next(Python2) 或者__next__方法,它就是一个迭代器。
迭代(Iteration)
当我们使用一个循环来遍历某个东西时,这个过程本身就叫迭代。
生成器(Generators)
生成器也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。 它们并不返回一个值,而是yield(暂且译作“生出”)一个值。
def generator_function():
for i in range(10):
yield i
for item in generator_function():
print(item)
# Output: 0
# 1
# 2
...
# 9
生成器最佳应用场景是:你不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环。
4.2 协程(Coroutines)
Python中的协程和生成器很相似但又稍有不同。主要区别在于:
- 生成器是数据的生产者
- 协程则是数据的消费者
search = grep('coroutine')
next(search)
#output: Searching for coroutine
search.send("I love you")
search.send("Don't you love me?")
search.send("I love coroutine instead!")
#output: I love coroutine instead!
发送的值会被yield接收。我们为什么要运行next()方法呢?这样做正是为了启动一个协程。就像协程中包含的生成器并不是立刻执行,而是通过next()方法来响应send()方法。因此,你必须通过next()方法来执行yield表达式。
我们可以通过调用close()方法来关闭一个协程。像这样:
search = grep('coroutine')
search.close()
4.3 Classes
类变量和实例变量
class SuperClass(object):
pi = 3.14
superpowers = []
def __init__(self, name):
self.name = name
def add_superpower(self, power):
self.superpowers.append(power)
foo = SuperClass('foo')
bar = SuperClass('bar')
foo.name
# Output: 'foo'
bar.name
# Output: 'bar'
foo.add_superpower('fly')
bar.superpowers
# Output: ['fly']
foo.superpowers
# Output: ['fly']
foo.pi
# 3.14
bar.pi
# 3.14
foo.pi = 300
foo.pi
# 300
bar.pi
# 3.14s
旧式类和新式类
- 旧式类不继承任何内容
- 新式类继承自object
- python3全是新式类
魔法方法
-
init 创建实例时执行
-
getitem 实现了这个方法,可以用下标获取属性
class GetTest(object):
def __init__(self):
self.info = {
'name':'Yasoob',
'country':'Pakistan',
'number':12345812
}
def __getitem__(self,i):
return self.info[i]
foo = GetTest()
foo['name']
# Output: 'Yasoob'
foo['number']
# Output: 12345812
5、Data types
5.1 Collections
defaultdict
- 与dict类型不同,你不需要检查key是否存在
from collections import defaultdict
colours = (
('Yasoob', 'Yellow'),
('Ali', 'Blue'),
('Arham', 'Green'),
('Ali', 'Black'),
('Yasoob', 'Red'),
('Ahmed', 'Silver'),
)
favourite_colours = defaultdict(list)
for name, colour in colours:
favourite_colours[name].append(colour)
print(favourite_colours)
# defaultdict(<type 'list'>,
# {'Arham': ['Green'],
# 'Yasoob': ['Yellow', 'Red'],
# 'Ahmed': ['Silver'],
# 'Ali': ['Blue', 'Black']
# })
- 当你在一个字典中对一个键进行嵌套赋值时,如果这个键不存在,会触发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"
##运行正常
counter
Counter是一个计数器,它可以帮助我们针对某项数据进行计数
from collections import Counter
colours = (
('Yasoob', 'Yellow'),
('Ali', 'Blue'),
('Arham', 'Green'),
('Ali', 'Black'),
('Yasoob', 'Red'),
('Ahmed', 'Silver'),
)
favs = Counter(name for name, colour in colours)
print(favs)
## 输出:
## Counter({
## 'Yasoob': 2,
## 'Ali': 2,
## 'Arham': 1,
## 'Ahmed': 1
## })
deque
deque提供了一个双端队列,你可以从头/尾两端添加或删除元素。
from collections import deque
d = deque()
d.append('1')
d.append('2')
d.append('3')
print(len(d))
## 输出: 3
print(d[0])
## 输出: '1'
print(d[-1])
## 输出: '3'
d = deque(range(5))
print(len(d))
## 输出: 5
d.popleft()
## 输出: 0
d.pop()
## 输出: 4
print(d)
## 输出: deque([1, 2, 3])
我们也可以限制这个列表的大小
d = deque(maxlen=30)
d = deque([1,2,3,4,5])
d.extendleft([0])
d.extend([6,7,8])
print(d)
## 输出: deque([0, 1, 2, 3, 4, 5, 6, 7, 8])
namedtuple
from collections import namedtuple
Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="perry", age=31, type="cat")
print(perry)
## 输出: Animal(name='perry', age=31, type='cat')
print(perry.name)
## 输出: 'perry'
print(perry[0])
## 输出: 'perry'
enum.Enum (Python 3.4+)
from collections import namedtuple
from enum import Enum
class Species(Enum):
cat = 1
dog = 2
horse = 3
Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="Perry", age=31, type=Species.cat)
drogon = Animal(name="Drogon", age=4, type=Species.dragon)
tom = Animal(name="Tom", age=75, type=Species.cat)
#有三种方法访问枚举数据,例如以下方法都可以获取到’cat’的值:
Species(1)
Species['cat']
Species.cat
5.2 对象变动(Mutation)
foo = ['hi']
print(foo)
# Output: ['hi']
bar = foo
bar += ['bye']
print(foo)
# Output: ['hi', 'bye']
对象可变性(mutability)可能会引起一些问题:
def add_to(num, target=[]):
target.append(num)
return target
add_to(1)
# Output: [1]
add_to(2)
# Output: [1, 2]
add_to(3)
# Output: [1, 2, 3]
通过一些方法规避该类问题
def add_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
5.3 slots Magic
默认情况下Python用一个字典来保存一个对象的实例属性。 使用__slots__来告诉Python不要使用字典,而且只给一个固定集合的属性分配空间
- 不使用__slots__
class MyClass(object): def __init__(self, name, identifier): self.name = name self.identifier = identifier self.set_up() # ...
- 使用__slots__
class MyClass(object): __slots__ = ['name', 'identifier'] def __init__(self, name, identifier): self.name = name self.identifier = identifier self.set_up() # ...
第二段代码会为你的内存减轻负担,内存占用率几乎40%~50%的减少。
6、Decorators
6.1 What is a decorator?
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
但是还存在个小瑕疵,可以通过wraps解决
print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey yo! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
- 授权
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
- 日志
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
- 装饰器类
# 日志装饰器类
from functools import wraps
class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile
def __call__(self, func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile并写入
with open(self.logfile, 'a') as opened_file:
# 现在将日志打到指定的文件
opened_file.write(log_string + '\n')
# 现在,发送一个通知
self.notify()
return func(*args, **kwargs)
return wrapped_function
def notify(self):
# logit只打日志,不做别的
pass
@logit()
def myfunc1():
pass
- 添加子类
class email_logit(logit):
'''
一个logit的实现版本,可以在函数调用时发送email给管理员
'''
def __init__(self, email='admin@myproject.com', *args, **kwargs):
self.email = email
super(email_logit, self).__init__(*args, **kwargs)
def notify(self):
# 发送一封email到self.email
pass
从现在起,@email_logit将会和@logit产生同样的效果,但是在打日志的基础上,还会多发送一封邮件给管理员。
6.2 Function caching
#py3.2+ 新特性
from functools import lru_cache
#maxsize描述lru_cache最多缓存最近多少个返回值。
@lru_cache(maxsize=32)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> print([fib(n) for n in range(10)])
#Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
#清空缓存
fib.cache_clear()
#py2 手动通过装饰器实现该功能
from functools import wraps
def memoize(function):
memo = {}
@wraps(function)
def wrapper(*args):
try:
return memo[args]
except KeyError:
rv = function(*args)
memo[args] = rv
return rv
return wrapper
@memoize
def fibonacci(n):
if n < 2: return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(25)
7、其他
7.1 One Liners
一些单行命令
* 起server
#Python 2
python -m SimpleHTTPServer
#Python 3
python -m http.server
* 漂亮的打印
from pprint import pprint
my_dict = {'name': 'Yasoob', 'age': 'undefined', 'personality': 'awesome'}
pprint(my_dict)
7.2 兼容Python2和Python3
- Future模块导入 导入__future__模块,它可以帮你在Python2中导入Python3的功能
print
# Output:
from __future__ import print_function
print(print)
# Output: <built-in function print>
- 重命名模块
try: import urllib.request as urllib_request # for Python 3 except ImportError: import urllib2 as urllib_request # for Python 2
- 通过引入包强制放弃过期的Python2内置功能
from future.builtins.disabled import * apply() # Output: NameError: obsolete Python 2 builtin apply is disabled
- 标准库向下兼容的外部支持 有一些包在非官方的支持下为Python2提供了Python3的功能
- enum pip install enum34
- singledispatch pip install singledispatch
- pathlib pip install pathlib
7.3 Python C extensions
- ctypes
ctypes模块提供了和C语言兼容的数据类型和函数来加载dll文件,因此在调用时不需对源文件做任何的修改。也正是如此奠定了这种方法的简单性。
- 写代码
- 编译为.so(windows为dll)
- python中引入,调用编译后文件
from ctypes import * ...
- SWIG 开发人员必须编写一个额外的接口文件来作为SWIG(终端工具)的入口。
- Python/C API 需要以特定的方式来编写C代码以供Python去调用它。所有的Python对象都被表示为一种叫做PyObject的结构体,并且Python.h头文件中提供了各种操作它的函数。 原文链接