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

函数以及函数式编程

到目前为止,我们的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)

#此刻定义一个函数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**2
map(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+y
print(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('insid
change_and_print_global:',animal)
... animal = 'dog'
... print('after the change:',animal)
...
>>> change_and_print_global()
Traceback (most recent call last):
File "", line 1, in 
File "", line 2, in
change_and_print_global
UnboundLocalError: local variable
'animal' referenced before assignment

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

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

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

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

生成器

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

def my_range(first, last, step=1):
    n = first
    while n

装饰器

参考文章1,参考文章2

名称中_和__的用法

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

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

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

你可能感兴趣的:(python -- 函数以及函数式编程)