函数:命名空间、多个值返回、函数作为对象、Lambda; 生成器:生成器表达式、itertools; 错误与异常捕获:try 语句的使用;
Python 函数
参数
函数是实现代码复用与组织化最重要的方法,函数用 def 关键字定义:
1 | def my_func(x,y,z=1.5): |
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 | def func(): |
func()函数调用后,在它的内部创建了一个空的数组,然后5个元素添加了进去,但当函数运行结束后,a马上就会被销毁。
假设将代码改成这样:
1 | a = [] |
修改函数外面的变量是可能的,但这些变量必须声明为 global 类型:
1 | a = None |
个人不是很推荐使用 global 关键字,通常来说全局变量都用来存储一些系统的状态,如果你需要大量的使用,更推荐你用更面向对象的方式,例如类。
返回多个值
1 | def f(): |
python的函数可以返回多个值,它们会被包装成一个元组,随后再被解包。
函数作为对象
因为python的函数也是对象,所以可以做很多别的语言很难做到的事情。 假设我们有一些数据需要清理:
1 | states = [' Alabama ', 'Georgia!', 'Georgia', 'georgia', 'FlOrIda','south carolina##', 'West virginia?'] |
如果你处理过用户提交上来的数据就懂我说的,很多简直想象不到输入都会发生,对于那些输入,我们要去掉首尾空格,多余的符号,正确的首字母大小写等等。一种方法是,我们可以用自带的re正则模块:
1 | import re |
上面的结果看起来是这样的:
1 | clean_strings(states) |
我们函数作为对象,存到数组中,来实现这一需求:
1 | def remove_punctuation(value): |
这种方式可以让你的代码更解耦。
用map方法也可以将一个函数作用到序列的每一个元素上:
1 | for x in map(remove_punctuation,states): |
Lambda
Lambda是把那些很简短的函数形式做了简化,让你可以用一种非常简单的方式定义一个函数,然后将这个小函数用在需要它的地方,这在特定的情境下,非常方便:
1 | def short_function(x): |
看下面代码:
1 | def apply_to_list(some_list,f): |
你可以在参数中,直接定义要传进去的参数。
再来看另一个例子,你有一堆字符,你需要根据每一个字符中字母出现的个数多少来排序(重复的不算):
1 | strings = ['foo', 'card', 'bar', 'aaaa', 'abab'] |
- list,会将字母串分解
- set,会去掉重复的字母
最后算出每个字母串的长度并以此排序。
lambda函数是没有__name__属性的
生成器
可以将iter函数作用到序列上,这样便返回了一个生成器。
1 | dict_iterator = iter(some_dict) |
可以用list包含一个生成器,得到内部的值:
1 | list(dict_iterator) |
生成器是惰性的,比如你要读一个文件有一万行,你不需要一次性全部的读取,用生成器,你只需要一行一行的返回。
生成器表达式
生成器表达式和列表推导式有些类似,不过包裹它的是括号:
1 | gen = (x ** 2 for x in range(100)) |
上面这种写法和下面的代码完全一样:
1 | def make_gen(): |
生成器可以像数组一样当作函数的参数,比如计算list內所有数的和:
1 | gen = [x ** 2 for x in range(100)] |
itertools
itertools标准库为一些常用的数据,内置了一些通用的生成器。
1 | import itertools |
错误与异常捕获
健壮的程序一定要有错误与异常捕获,我么要进行类型转化:
1 | float('1.2345') ---> 1.2345 |
我们定义一个函数来捕获这个异常:
1 | def attemp_float(x) |
这时候,如果捕获到了value error,就会返回输出的数据:
1 | float('1.2345') ---> 1.2345 |
函数有可能会返回别的错误,这时候需要把可能出现的错误写出来:
1 | ... |
在文件读取中,你打开了一个文件,不管你有没有操作,你都需要把它关闭,这时候就需要用到final语句,即不管前面是否捕获到了异常,最终都要做的事情:
1 | f = open(path,'w') |