函数:命名空间、多个值返回、函数作为对象、Lambda;
生成器:生成器表达式、itertools;
错误与异常捕获:try 语句的使用;
参数
函数是实现代码复用与组织化最重要的方法,函数用 def 关键字定义:
1
2
3
4
5def my_func(x,y,z=1.5):
if z>1:
return z*(x+y)
else:
return z/(x+y)
python中返回多个值也是没问题的,如果你写的函数没有返回值,那么默认python会返回 None.
每个函数都有 positional arguments 和 keyword arguments. keyword arguments 在设置函数的默认参数的时候用的比较多,在前面的函数中,x和y是 positional arguments,而z是 keyword arguments。
这些参数的顺序是有限制的:
keyword arguments must follow the positional arguments(if any).
命名空间
函数可以访问两种类型的变量,global 和 local 的,中文叫全局的或局部的。
局部变量在函数运行的时候马上创建,如果函数运行完毕,马上会被销毁(也有例外,但不在这里的讨论范围之内)。
比如下面的函数:
1
2
3
4def func():
a = []
for i in range(5):
a.append(i)
func()函数调用后,在它的内部创建了一个空的数组,然后5个元素添加了进去,但当函数运行结束后,a马上就会被销毁。
假设将代码改成这样:
1
2
3
4a = []
def func():
for i in range(5):
a.append(i)
修改函数外面的变量是可能的,但这些变量必须声明为 global 类型:
1
2
3
4
5a = None
def bind_a_variable():
global a
a = []
bind_a_variable() # 输出 []
个人不是很推荐使用 global 关键字,通常来说全局变量都用来存储一些系统的状态,如果你需要大量的使用,更推荐你用更面向对象的方式,例如类。
返回多个值1
2
3
4
5def f():
a = 5
b = 6
c = 7
return a,b,c
python的函数可以返回多个值,它们会被包装成一个元组,随后再被解包。
函数作为对象
因为python的函数也是对象,所以可以做很多别的语言很难做到的事情。
假设我们有一些数据需要清理:
1states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda','south carolina##', 'West virginia?']
如果你处理过用户提交上来的数据就懂我说的,很多简直想象不到输入都会发生,对于那些输入,我们要去掉首尾空格,多余的符号,正确的首字母大小写等等。一种方法是,我们可以用自带的re正则模块:
1
2
3
4
5
6
7
8
9import re
def clean_strings(strings):
result = []
for value in strings:
value = value.strip()
value = re.sub('[!#?]','',value)
value = value.title()
result = append(value)
上面的结果看起来是这样的:
1
2
3clean_strings(states)
输出:
['Alabama','Georgia', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']
我们函数作为对象,存到数组中,来实现这一需求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18def remove_punctuation(value):
return re.sub('[!#?]', '', value)
# 函数数组
clean_ops = [str.strip,remove_punctuation,str.title]
# ops参数接受函数数组对象
def clean_string(strings,ops):
result = []
for value in strings:
for function in ops:
value = function(value)
result.append(value)
return result
clean_string(states,clean_ops)
输出是一样的:
['Alabama','Georgia', 'Georgia', 'Georgia', 'Florida', 'South Carolina', 'West Virginia']
这种方式可以让你的代码更解耦。
用map方法也可以将一个函数作用到序列的每一个元素上:
1
2for x in map(remove_punctuation,states):
print(x)
Lambda
Lambda是把那些很简短的函数形式做了简化,让你可以用一种非常简单的方式定义一个函数,然后将这个小函数用在需要它的地方,这在特定的情境下,非常方便:
1
2
3
4def short_function(x):
return x* 2
# 等于
equiv_anon = lambda x: x*2
看下面代码:
1
2
3
4
5def apply_to_list(some_list,f):
return [f(x) for x in some_list]
ints = [1,2,3,4]
apply_to_list(ints,lambdax:x*2)
你可以在参数中,直接定义要传进去的参数。
再来看另一个例子,你有一堆字符,你需要根据每一个字符中字母出现的个数多少来排序(重复的不算):
1
2strings = ['foo', 'card', 'bar', 'aaaa', 'abab']
strings.sort(key= lambda x: len(set(list(x))))
list,会将字母串分解
set,会去掉重复的字母
最后算出每个字母串的长度并以此排序。
lambda函数是没有name属性的
生成器
可以将iter函数作用到序列上,这样便返回了一个生成器。
1
2
3
4dict_iterator = iter(some_dict)
dict_iterator
输出:
可以用list包含一个生成器,得到内部的值:
1list(dict_iterator)
生成器是惰性的,比如你要读一个文件有一万行,你不需要一次性全部的读取,用生成器,你只需要一行一行的返回。
生成器表达式
生成器表达式和列表推导式有些类似,不过包裹它的是括号:
1
2
3gen = (x ** 2 for x in range(100))
gen
# 输出 at 0x109cbf3b8>
上面这种写法和下面的代码完全一样:
1
2
3
4def make_gen():
for x in range(100):
yield x**2
gen = make_gen()
生成器可以像数组一样当作函数的参数,比如计算list內所有数的和:
1
2
3
4
5gen = [x ** 2 for x in range(100)]
sum(gen) # 输出328350
gen = (x ** 2 for x in range(100))
sum(gen) # 生成器当作参数,一样输出328350
itertools
itertools标准库为一些常用的数据,内置了一些通用的生成器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14import itertools
first_letter = lambda x: x[0]
names = ['Alan', 'Adam', 'Wes', 'Will', 'Albert', 'Steven']
for letter, names in itertools.groupby(names, first_letter):
print(letter, list(names)) # names is a generator
# 输出
A ['Alan', 'Adam']
W ['Wes', 'Will']
A ['Albert']
S ['Steven']
错误与异常捕获
健壮的程序一定要有错误与异常捕获,我么要进行类型转化:
1
2float('1.2345') ---> 1.2345
float('string') ---> value error
我们定义一个函数来捕获这个异常:
1
2
3
4
5def attemp_float(x)
tyr:
return float(x)
except:
return x
这时候,如果捕获到了value error,就会返回输出的数据:
1
2float('1.2345') ---> 1.2345
float('string') ---> string
函数有可能会返回别的错误,这时候需要把可能出现的错误写出来:
1
2
3...
except(TypeError,ValueError)
...
在文件读取中,你打开了一个文件,不管你有没有操作,你都需要把它关闭,这时候就需要用到final语句,即不管前面是否捕获到了异常,最终都要做的事情:
1
2
3
4
5f = open(path,'w')
try:
write_to_file(f)
finally:
f.close()