01. Python 工具
02. Python 基础
03. Numpy
- Numpy 简介
- Matplotlib 基础
- Numpy 数组及其索引
- 数组类型
- 数组方法
- 数组排序
- 数组形状
- 对角线
- 数组与字符串的转换
- 数组属性方法总结
- 生成数组的函数
- 矩阵
- 一般函数
- 向量化函数
- 二元运算
- ufunc 对象
- choose 函数实现条件筛选
- 数组广播机制
- 数组读写
- 结构化数组
- 记录数组
- 内存映射
- 从 Matlab 到 Numpy
04. Scipy
05. Python 进阶
- sys 模块简介
- 与操作系统进行交互:os 模块
- CSV 文件和 csv 模块
- 正则表达式和 re 模块
- datetime 模块
- SQL 数据库
- 对象关系映射
- 函数进阶:参数传递,高阶函数,lambda 匿名函数,global 变量,递归
- 迭代器
- 生成器
- with 语句和上下文管理器
- 修饰符
- 修饰符的使用
- operator, functools, itertools, toolz, fn, funcy 模块
- 作用域
- 动态编译
06. Matplotlib
- Pyplot 教程
- 使用 style 来配置 pyplot 风格
- 处理文本(基础)
- 处理文本(数学表达式)
- 图像基础
- 注释
- 标签
- figures, subplots, axes 和 ticks 对象
- 不要迷信默认设置
- 各种绘图实例
07. 使用其他语言进行扩展
- 简介
- Python 扩展模块
- Cython:Cython 基础,将源代码转换成扩展模块
- Cython:Cython 语法,调用其他C库
- Cython:class 和 cdef class,使用 C++
- Cython:Typed memoryviews
- 生成编译注释
- ctypes
08. 面向对象编程
09. Theano 基础
- Theano 简介及其安装
- Theano 基础
- Theano 在 Windows 上的配置
- Theano 符号图结构
- Theano 配置和编译模式
- Theano 条件语句
- Theano 循环:scan(详解)
- Theano 实例:线性回归
- Theano 实例:Logistic 回归
- Theano 实例:Softmax 回归
- Theano 实例:人工神经网络
- Theano 随机数流变量
- Theano 实例:更复杂的网络
- Theano 实例:卷积神经网络
- Theano tensor 模块:基础
- Theano tensor 模块:索引
- Theano tensor 模块:操作符和逐元素操作
- Theano tensor 模块:nnet 子模块
- Theano tensor 模块:conv 子模块
10. 有趣的第三方模块
11. 有用的工具
- pprint 模块:打印 Python 对象
- pickle, cPickle 模块:序列化 Python 对象
- json 模块:处理 JSON 数据
- glob 模块:文件模式匹配
- shutil 模块:高级文件操作
- gzip, zipfile, tarfile 模块:处理压缩文件
- logging 模块:记录日志
- string 模块:字符串处理
- collections 模块:更多数据结构
- requests 模块:HTTP for Human
12. Pandas
函数进阶:参数传递,高阶函数,lambda 匿名函数,global 变量,递归
函数是基本类型
在 Python
中,函数是一种基本类型的对象,这意味着
- 可以将函数作为参数传给另一个函数
- 将函数作为字典的值储存
- 将函数作为另一个函数的返回值
In [1]:
def square(x):
"""Square of x."""
return x*x
def cube(x):
"""Cube of x."""
return x*x*x
作为字典的值:
In [2]:
funcs = {
'square': square,
'cube': cube,
}
例子:
In [3]:
x = 2
print square(x)
print cube(x)
for func in sorted(funcs):
print func, funcs[func](x)
4
8
cube 8
square 4
函数参数
引用传递
Python
中的函数传递方式是 call by reference
即引用传递,例如,对于这样的用法:
x = [10, 11, 12]
f(x)
传递给函数 f
的是一个指向 x
所包含内容的引用,如果我们修改了这个引用所指向内容的值(例如 x[0]=999
),那么外面的 x
的值也会被改变。不过如果我们在函数中赋给 x
一个新的值(例如另一个列表),那么在函数外面的 x
的值不会改变:
In [4]:
def mod_f(x):
x[0] = 999
return x
x = [1, 2, 3]
print x
print mod_f(x)
print x
[1, 2, 3]
[999, 2, 3]
[999, 2, 3]
In [5]:
def no_mod_f(x):
x = [4, 5, 6]
return x
x = [1,2,3]
print x
print no_mod_f(x)
print x
[1, 2, 3]
[4, 5, 6]
[1, 2, 3]
默认参数是可变的!
函数可以传递默认参数,默认参数的绑定发生在函数定义的时候,以后每次调用默认参数时都会使用同一个引用。
这样的机制会导致这种情况的发生:
In [6]:
def f(x = []):
x.append(1)
return x
理论上说,我们希望调用 f()
时返回的是 [1]
, 但事实上:
In [7]:
print f()
print f()
print f()
print f(x = [9,9,9])
print f()
print f()
[1]
[1, 1]
[1, 1, 1]
[9, 9, 9, 1]
[1, 1, 1, 1]
[1, 1, 1, 1, 1]
而我们希望看到的应该是这样:
In [8]:
def f(x = None):
if x is None:
x = []
x.append(1)
return x
print f()
print f()
print f()
print f(x = [9,9,9])
print f()
print f()
[1]
[1]
[1]
[9, 9, 9, 1]
[1]
[1]
高阶函数
以函数作为参数,或者返回一个函数的函数是高阶函数,常用的例子有 map
和 filter
函数:
map(f, sq)
函数将 f
作用到 sq
的每个元素上去,并返回结果组成的列表,相当于:
[f(s) for s in sq]
In [9]:
map(square, range(5))
Out[9]:
[0, 1, 4, 9, 16]
filter(f, sq)
函数的作用相当于,对于 sq
的每个元素 s
,返回所有 f(s)
为 True
的 s
组成的列表,相当于:
[s for s in sq if f(s)]
In [10]:
def is_even(x):
return x % 2 == 0
filter(is_even, range(5))
Out[10]:
[0, 2, 4]
一起使用:
In [11]:
map(square, filter(is_even, range(5)))
Out[11]:
[0, 4, 16]
reduce(f, sq)
函数接受一个二元操作函数 f(x,y)
,并对于序列 sq
每次合并两个元素:
In [12]:
def my_add(x, y):
return x + y
reduce(my_add, [1,2,3,4,5])
Out[12]:
15
传入加法函数,相当于对序列求和。
返回一个函数:
In [13]:
def make_logger(target):
def logger(data):
with open(target, 'a') as f:
f.write(data + '\n')
return logger
foo_logger = make_logger('foo.txt')
foo_logger('Hello')
foo_logger('World')
In [14]:
!cat foo.txt
Hello
World
In [15]:
import os
os.remove('foo.txt')
匿名函数
在使用 map
, filter
,reduce
等函数的时候,为了方便,对一些简单的函数,我们通常使用匿名函数的方式进行处理,其基本形式是:
lambda <variables>: <expression>
例如,我们可以将这个:
In [16]:
print map(square, range(5))
[0, 1, 4, 9, 16]
用匿名函数替换为:
In [17]:
print map(lambda x: x * x, range(5))
[0, 1, 4, 9, 16]
匿名函数虽然写起来比较方便(省去了定义函数的烦恼),但是有时候会比较难于阅读:
In [18]:
s1 = reduce(lambda x, y: x+y, map(lambda x: x**2, range(1,10)))
print(s1)
285
当然,更简单地,我们可以写成这样:
In [19]:
s2 = sum(x**2 for x in range(1, 10))
print s2
285
global 变量
一般来说,函数中是可以直接使用全局变量的值的:
In [20]:
x = 15
def print_x():
print x
print_x()
15
但是要在函数中修改全局变量的值,需要加上 global
关键字:
In [21]:
x = 15
def print_newx():
global x
x = 18
print x
print_newx()
print x
18
18
如果不加上这句 global
那么全局变量的值不会改变:
In [22]:
x = 15
def print_newx():
x = 18
print x
print_newx()
print x
18
15
递归
递归是指函数在执行的过程中调用了本身,一般用于分治法,不过在 Python
中这样的用法十分地小,所以一般不怎么使用:
Fibocacci 数列:
In [23]:
def fib1(n):
"""Fib with recursion."""
# base case
if n==0 or n==1:
return 1
# recurssive caae
else:
return fib1(n-1) + fib1(n-2)
print [fib1(i) for i in range(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
一个更高效的非递归版本:
In [24]:
def fib2(n):
"""Fib without recursion."""
a, b = 0, 1
for i in range(1, n+1):
a, b = b, a+b
return b
print [fib2(i) for i in range(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
速度比较:
In [25]:
%timeit fib1(20)
%timeit fib2(20)
100 loops, best of 3: 5.35 ms per loop
100000 loops, best of 3: 2.2 µs per loop
对于第一个递归函数来说,调用 fib(n+2)
的时候计算 fib(n+1), fib(n)
,调用 fib(n+1)
的时候也计算了一次 fib(n)
,这样造成了重复计算。
使用缓存机制的递归版本,这里利用了默认参数可变的性质,构造了一个缓存:
In [26]:
def fib3(n, cache={0: 1, 1: 1}):
"""Fib with recursion and caching."""
try:
return cache[n]
except KeyError:
cache[n] = fib3(n-1) + fib3(n-2)
return cache[n]
print [fib3(i) for i in range(10)]
%timeit fib1(20)
%timeit fib2(20)
%timeit fib3(20)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
100 loops, best of 3: 5.37 ms per loop
100000 loops, best of 3: 2.19 µs per loop
The slowest run took 150.16 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 230 ns per loop
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论