python快速学习系列(3):函数式编程

之前如果学过别的编程语言的话,python学起来应该是非常快的。即使之前没有任何编程经历的话,python也是一门非常容易入手的语言。所以,让我们一鼓作气,快速入门!!!
本片博文的侧重点是函数式编程,主要讲述函数相关内容
话不多说,干货奉上


1.docstr,即文档字符串(也就是起说明作用的),在函数下面的第一句用三引号的语句称之为docstr,不会被执行,如:

def print_sigai():
    '''Just a function'''
    print('sigai')

另外,函数本身有__doc__属性,可以查看修改编辑docstr
如:

print_sigai.__doc__  #'Just a function'
print_sigai.__doc__ = 'Just an easy function'

通过以上可以看出,python中的函数确实是一个实例化的对象

2.help(函数名):在交互式解释器中可以通过help函数获得你想要知道的函数的使用方法
如:help(print)
不仅仅是python内置函数可以通过help调用,甚至自己编写的函数也可以。注意,在cmd命令行下,可以用help来查询函数、类等的使用方式和说明

3.python函数可以同时返回多个值,这多个值会形成一个tuple(所以也可以说只返回一个值)

4.参数、作用域
1)参数的传递
-实参的传递本质上是赋值
-既然是赋值,就啊哟看赋的对象是可变对象还是不可变对象
-把一个变量和它所在的地址想象成盒子里的东西和盒子外用于标识的标签
-可变对象赋值,赋的是标签
-不可变对象赋值,赋的是盒子本身

def f(a):
    a.append(1)
    return a
a = [1]
f(a) #返回[1,1]
a #a也跟着改变,是[1,1]

那么如何传递一个可变对象的同时不希望被函数修改呢?

i)f(a[:])#弄懂拷贝即可
ii)嵌套的List要使用copy.deepcopy

2)参数分类
-位置参数:按位置先后进行赋值

def say(name,str):
    print(name,'hi',str)
say('python','hello')

-关键字参数:赋值的时候指定参数名

def say(name,str):
    print(name,'hi',str)
say(name='python',str='hello')

-默认参数:在写函数的时候,给参数指定一个值,这样在调用的时候如果没有赋值,就使用默认值

def say(name='python',str='hello'):
    print(name,'hi',str)
say()

建议:
·最好不同时使用多个未知参数和多个关键字参数
·如果使用了关键字采纳数,位置参数越少越好,并且集中放在最前面

3)接受任意个参数:在参数前面加*

def sum(*l):
    res = 0
    for i in l:
        res += i
    return res

与赋值不同,函数的参数用星号拆包或缝合时,得到的是元组tuple

a,*b,c = list(range(7)) #这里的b是list
def sum(*b):
    print(type(b))#这里的b是tuple

4)接受任意个关键字参数,两个星号

def register(**kw):
    print('kw's type is',type(kw))
    print('kw is',kw)
register(name='sigai',pi=3.14)
#结果是:
#kw's type is <class 'dict'>
#kw is {'name':'sigai','pi':3.14}

两个星号相当于接受的是字典,关键字参数(参数名=参数值),其中,参数名认为是
key,参数值认为是value

另外,也可以一起收集位置参数与关键字参数

def register(*list,**dict):
    print(list)
    print(dict)
register(1,2,3,name='sigai',pi=3.14)
#结果是:
#(1,2,3)
#{'name':'sigai','pi':3.14}

5)星号除了封包还可以拆包

def sum(a,b,c):
    return a+b+c
x=(1,2,3)#此处x内的元素个数必须和参数个数相等,而且,x可以是tuple也可以是list
sum(*x)

*简单总结:用在函数定义时是封包,用在函数调用时是拆包

6)在局部作用域里修改全局变量,加global

def f2():
    global name#如果没有这句话的话,就name不会变成s2,仍然为s1
    name = 's2'
    print(name)
if __name__ = '__main__':
    name = 's1'
    print(name)
    f2()
    print(name)

7)作用域的生命周期
·built-in:解释器在则在,解释器亡则亡
·global:导入模块时创建,直到解释器退出
·local:函数调用时才创建

5.函数式编程概述
·前提:函数在python中是一等对象
·工具:built-in高阶函数;lambda函数;operator模块,functools模块
·模式:闭包与装饰器
·替代:用List Comprehension可轻松替代map和filter(reduce替代起来比较困难)
·原则:No Side Effect
什么是No Side Effect?
-函数的所有功能就仅仅是返回一个新的值而已,没有其他行为,尤其是不得修改外部变量。
因而,各个独立的部分的执行顺序可以随意打乱,带来执行顺序上的自由
执行顺序的自由是的一系列新的特性得以实现:无锁的并发,惰性求值,编译器级别的优化等

6.一等函数
1)一等对象:
在运行时创建,能赋值给变量或数据结构中的元素,能作为参数传给函数,能作为函数的返回结果
2)python中,所有的函数都是一等对象,简称为一等函数
def say_hi():print(“hi”)
-能赋值给变量或数据结构中的元素
test = say_hi
test()

-能作为参数传递给函数

def repeat(f,num):
    [f() for i in range(num)]
repeat(say_hi,3)
#结果是打印三遍hi

-能作为函数的返回结果

def repeat_func(f,num):
    def new_func():
        [f() for i in range(num)]
    return new_func
repeated_func = repeat_func(say_hi,3)
repeated_func()
#结果是打印三遍hi

7.高阶函数
·定义:接受函数为参数,或把函数作为返回结果的函数
1)map高阶函数

x = map(square,range(10))  #square可看做是一个行为,对后面的每个对象做此行为

其实可以用 [x*x for x in range(10)]代替。自从有了List comprehension之后,map越来越鸡肋了
2)filter:过滤

x = [(),[],{},None,'',False,0,True,1,2,-3]
x_result = filter(bool,x)

#x_result保留了x中布尔值为True的元素
可用[i for i in x if bool(x)]代替
3)reduce函数

def multi(a,b):return a*b
from functools import reduce
reduce(multi,range(1,5))
#结果是24

reduce的功能是把一系列值,按照某一行为,两两组合,最后成为一个值
4)sorted,max,min
sorted中两个关键字参数:reverse,key
sorted默认的是按照从小到大的顺序排序,reverse=True可以使得从大到小进行排序
key传入的是一个函数,表示先对数据进行处理,然后在排序,如:

sorted([x * (-1)**x for x in range(10)],key=abs)
#结果是[0,-1,2,-3,4,-5,6,-7,8,-9]

#在排序前进行绝对值处理,然后再按照处理后的结果对元素进行排序
#但是这个key传入的函数是一个单输入单输出的函数
5)partial函数:作用是固定若干个参数(在程序越写越大,一个函数里面参数量非常大的时候适用)

abs_sorted = partial(sorted,key=abs)
abs_sorted([x * (-1)**x for x in range(10)])

8.匿名函数:
·定义:适用lambda表达式创建的函数,函数本身没有名字
·特点:只能适用纯表达式,不能赋值,不能适用while和try等块语句
·语法:lambda [arg1,[,arg2[,arg3…]]]:expression #参数个数0-无穷均可
能用一个表达式直接放到return里返回的函数都可以用lambda速写

multi = lambda x,y:x*y
multi(3,4)

List+lambda可以得到行为列表

f_list = [lambda x:x+1,lambda x:x**2,lambda x:x**3]
[f_list[j](10) for j in range(3)]

#结果是[11,100,1000]
f_list是一个定义了三个函数的列表,取f_list每个函数传入参数得到结果

惰性计算:

f_list = [lambda x:x**i for i in range(5)]
[f_list[j](10) for j in range(5)]

#结果是[10000,1000,10000,10000,10000]
#注意这里f_list只有一个函数,就是x**4

猜你喜欢

转载自blog.csdn.net/shanlepu6038/article/details/84670742
今日推荐