python -- 函数以及函数式编程

来源:互联网 发布:黄道日与黑道日的算法 编辑:程序博客网 时间:2024/06/05 18:46

函数以及函数式编程

到目前为止,我们的Python 代码已经实现了小的分块。它们都适合处理微小任务,

但是我们想复用这些代码,所以需要把大型代码织成可管理的代码段。代码复用的第一步是
使用函数,它是命名的用于区分的代码段。函数可以接受任何数字或者其他类型的输入作为参
数,并且返回数字或者其他类型的结果。

定义一个函数

为了定义Python 函数,你可以依次输入def、函数名、带有函数参数的圆括号,最后紧跟一个

冒号(:)。函数命名规范和变量命名一样(必须使用字母或者下划线_ 开头,仅能含有字母、
数字和下划线)。
我们先定义和调用一个没有参数的函数。下面的例子是最简单的Python 函数:

>>> def do_nothing():...  pass

定义一个无参数函数

现在,定义一个无参数,但打印输出一个单

词的函数:

>>> def make_a_sound():...     print('momoda')...>>> make_a_sound()momoda>>> def agree():...     return True...#或者,调用这个函数,使用if 语句检查它的返回值:>>> if agree():...     print("Is true")... else:...     print("Is Flase")...Is true

定义一个有参函数

>>> def echo(str):...     return str*2...>>> echo('abc')'abcabc'>>>def fruit_color(color):    if color == 'red':        print('这可能是一个苹果,或者是西红柿')    elif color == 'yellow':        print('这或许是一个香蕉也说不定')    elif color == 'blue':        print('一定是蓝莓吧')    else:        print('我可猜不到这是什么')fruit_color('red')

位置参数

下面创建一个带有位置参数的函数,并且返回一个字典:

def menu(a,b,c):    return {'a':a,'b':b,'c':c}print(menu('a','b','c’)){'a': 'a', 'b': 'b', 'c': 'c’}#尽管这种方式很常见,但是位置参数的一个弊端是必须熟记每个位置的参数的含义。在调#用函数menu() 时误把最后一个参数当作第一个参数,会得到完全不同的结果:print(menu('c','b','a')){'c': 'a', 'b': 'b', 'a': 'c'}

关键字参数

为了避免位置参数带来的混乱,调用参数时可以指定对应参数的名字,甚至可以采用与函

数定义不同的顺序调用:

def menu(a,b,c):    return {'a':a,'b':b,'c':c}print(menu(c='c',b='b',a='a’))当然也可以混合使用def menu(a,b,c):    return {'a':a,'b':b,'c':c}print(menu(a='a',c='c',b='b'))。

指定默认参数值

举例:

def menu(a,b,c):    return {'a':a,'b':b,'c':c}print(menu(c='b',b='a’))

报错,缺少参数,实际上我们可以设置参数默认值

def menu(a='a',b='b',c='c'):    return {'a':a,'b':b,'c':c}print(menu(c='b',b='a’))print(menu())

使用*收集位置参数

当参数被用在函数内部时, 星号将一组可变数量的位置参数集合成参数值的元组。

def my_print(*Str):    print(Str)my_print()()my_print(1,2,3,4,5):(1, 2, 3, 4, 5)my_print(1,2,3,'let\'s go’)(1, 2, 3, "let's go")

使用两个星号可以将参数收集到一个字典中,参数的名字是字典的键,对应参数的值是字

典的值。下面的例子定义了函数print_kwargs(),然后打印输出它的关键字参数:

def my_print(**abc):    print(abc)my_print(a='a',b='b',c='c')

函数本身也是一个对象

之前提过Python 中一切都是对象,包括数字、字符串、元组、列表、字典和函数。函数是Python 中的一等公民,可以把它们(返回值)赋给变量,可以作为参 数被其他函数调用,也可以从其他函数中返回值。它可以帮助你在Python 中实现其 他语言难以实现的功能。

#为了测试,现在定义一个简单的函数answer(),它没有任何参数,仅仅打印输出数字42:>>> def answer():... print(42)#运行该函数,会得到下面的结果:>>> answer()42#再定义一个函数run_something。它有一个参数func,这个参数是一个可以运行的函数的名字:>>> def run_something(func):...  func()#将参数answer 传到该函数,在这里像之前碰到的一样,把函数名当作数据使用:>>> run_something(answer)42#########################################我们来运行一个带参数的例子。定义函数add_args(),它会打印输出两个数值参数(arg1和arg2)的和:>>> def add_args(arg1, arg2):... print(arg1 + arg2)#那么,add_args() 的类型是什么?>>> type(add_args)<class 'function'>#此刻定义一个函数run_something_with_args(),它带有三个参数:#• func——可以运行的函数#• arg1——func 函数的第一个参数#• arg2——func 函数的第二个参数>>> def run_something_with_args(func, arg1,arg2):        add_args(arg1, arg2)>>> run_something_with_args(add_args, 5, 9)14

内部函数

内部函数可以看作一个闭包。闭包是一个可以由另一个函数动态生成的函数,并且可以改变和存储函数外创建的变量的值。

>>> def outer(a, b):    ... def inner(c, d):        ... return c + d    ... return inner(a, b)...>>>>>> outer(4, 7)11#########################def fun5():    def sayhello(name):        print("hello ", name)    return sayhello     #返回的是函数名称fun5()("zhangsan")

匿名函数:lambda()函数

edit_story(stairs, lambda word: word.capitalize() + '!')

map

map(funcname, list)

map(function, sequence[, sequence, …]) -> list:将function作用于给定序列的每一个元素,

并将结果作为list返回;如果函数中需要多个参数则从多个序列中读取(python3里面,map()
的返回值已经不再是list,而是iterators, 所以想要使用,只用将iterator 转换成list 即可)

def square(x):    return x**2map(square, [1,2,3,4,5])f1 = lambda x:x**2  #lambda表达式就是一个匿名函数print(f1(3))i1 = map(f1, [1,2,3,4,5])print(list(i1))

reduce

reduce(function, sequence[, initial]) -> value:与map相比 , reduce类似于一个聚合类的

应用方法, 把list中的参数, 依次传递给funcname, 每次funcname的参数都是上个funcname
执行结果和下一个list中的元素, 所以, funcname 的 参数必须是两个. 从执行过程看, 有点像递
归.如果指定了initial则首先从此值和第一个元素开始计算。

def sum(x,y):    return x+yprint(functools.reduce(sum, [1, 2, 3, 4, 5]))print(functools.reduce(lambda x,y:x+y, [1,2,3,4,5]))print(functools.reduce(lambda x,y:max([x,y]), [1,2,3,4,5]))

filter()

filter(function or None, sequence) -> list,tuple,string:

调用一个布尔类型的函数来迭代遍历每个seq中的元素,返回使得func返回为true的

元素的序列。

print(list(filter(lambda x:isinstance(x, (int)), [1,2,"3"])))print(list(filter(lambda x:x>2, [1,2,3])))

sorted

sorted( list, [comp_func])

排序方法, 第二个是可选参数, 根据可选参数返回的值, 对结果进行排序, comp_func

接受两个参数(x, y), 最终返回的结果应该是-1.0,1, 如果返回的是-1, 表示x , 0表示x=y,
1表示x>y, 所以, 实际的排序可以自定义

print(sorted([4,6,1,2,3]))print(sorted([4,6,1,2,3], reverse=True))print(sorted([1,2,3,4,5,6],key=cmp_to_key(lambda x,y:y-x)))

命名空间和作用域

一个名称在不同的使用情况下可能指代不同的事物。Python 程序有各种各样

的命名空间,它指的是在该程序段内一个特定的名称是独一无二的,它和其他同名的
命名空间是无关的。每一个函数定义自己的命名空间。如果在主程序(main)中定义
一个变量x,在另外一个函数中也定义x 变量,两者指代的是不同的变量。

每个程序的主要部分定义了全局命名空间。因此,在这个命名空间的变量是

全局变量。

animal = 'cat'>>> def print_global():. . . print('inside print_global:',animal). . .>>> print('outside print_global:',animal)outside print_global: cat>>> print_global()inside print_global: cat#####################在函数中改变全局变量,会报错:>>> def change_and_print_global():... print('insidchange_and_print_global:',animal)... animal = 'dog'... print('after the change:',animal)...>>> change_and_print_global()Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 2, inchange_and_print_globalUnboundLocalError: local variable'animal' referenced before assignment

如果在函数中不声明关键字global,Python 会使用局部命名空间,同时变量也是局

部的。函数执行后回到原来的命名空间。
Python 提供了两个获取命名空间内容的函数:

• locals() 返回一个局部命名空间内容的字典;

• globals() 返回一个全局命名空间内容的字典。

生成器

生成器是用来创建Python 序列的一个对象。目的就是为了避免一下子生成的数据太多占用大量内存,生成器会在数据被用到时生成数据。

def my_range(first, last, step=1):    n = first    while n<last:        yield n #yield是一个关键字,使用yeild的函数实际上一个生成器        n+=stepprint(my_range())#<generator object my_range at 0x0000021FC5AE>

装饰器

参考文章1,参考文章2

名称中_和__的用法

以两个下划线__ 开头和结束的名称都是Python 的保留用法。因此,在自定义的变量

中不能使用它们。选择这种命名模式是考虑到开发者一般是不会选择它们作为自己的
变量的。

if __name__ == '__main__':    print("这里是入口")