py函数式编程(高阶函数map/reduce/filter/sorted、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial())

#py函数式编程.py
#高阶函数map/reduce/filter/sorted、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial()


# =============================================================================
# #Py函数式编程.py
# #高阶函数、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial()
# #参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017328525009056
# =============================================================================

'''
深入:
一、import functools  
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。

1、使用:@functools.wraps(func)
通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

2、#使用:functools.partial()用来创建一个偏函数,即把一个函数的某些参数给固定住(即设置默认值),返回一个新函数。
#注意:偏函数实质上是一个 @装饰器 的原理,即在参数列表里追加进去 设置默认值的参数。
#如:int2('1000') 实则是运行的 int('1000',base=2)



#使用:
一、高阶函数(map/reduce/filter/sorted等)
高阶函数就是一个函数就可以接收另一个函数作为参数的函数。

1、map(func,*iterables)     将参数func函数 作用于 参数*iterables里的每一个内容,返回一个可迭代对象。
#注意 map(,)返回一个迭代器iterator,需要序列化才能输出。
`
2、reduce(func,*iterables,initial)  将参数func函数 作用于 参数序列上,并把结果继续和序列的下一个元素做累计计算。并最终返回值。
#注意 reduce(,) 直接返回累计作用的值。

3、filter(func,iters) 过滤序列序列。用参数func函数 过滤 参数iters序列,为True则留下,为False则丢弃。 
#注意 filter(,)返回一个迭代器iterator,需要序列化才能输出。

4、sorted(iterable, key=None, reverse=False) 对参数iterable序列list进行排序,
#注意 参数key可用来接收一个函数来实现自定义的排序。
#注意 参数reverse为True则反向排序


二、返回函数(闭包)
闭包函数
#高阶函数除了可以接受函数作为参数外,还可以把函数作为 结果值返回。
#闭包 即在 外部函数中 又定义了 内部函数,并且,内部函数 可以引用 外部函数 的参数和局部变量。
#当 外部函数 返回 内部函数 时,相关参数和变量都保存在返回的函数中,这种闭包程序结构拥有极大的威力,称谓“闭包”。
#参考网址:https://blog.csdn.net/sc_lilei/article/details/80464645

1、使用:通过获取主函数的魔法属性__closure__返回的值来确定主函数是否存在闭包。
#__closure__属性返回一个元组对象,包含了闭包引用的外部变量。
#对闭包主函数的__closure__属性迭代后通过cell_contents来输出闭包引用的外部变量
#如果主函数 没有return子函数,就不存在闭包,主函数不存在_closure__属性,返回None
#如果主函数 return的子函数不引用外部变量,也就不存在闭包,主函数的__closure__属性同样返回None。 

2、注意:闭包函数中的return返回内容指向(return返回子函数名称 而不是调用函数)、函数作用域。

3、注意:闭包时牢记一点:返回函数(子函数、内部函数)不要引用任何 循环变量,或者后续会发生变化的变量。
#如果子函数一定要引用循环变量,方法是再创建一个函数。
#用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:


三、匿名函数lambda
#关键字lambda表示匿名函数,lambda x : x*x,冒号前面表示函数参数,冒号后面表达式表示函数内容
1、#使用:匿名函数可以赋值变量,lambda也是一个函数对象,也可以赋值给变量,然后通过变量来调用匿名函数。
2、#使用:匿名函数可以作为返回值返回,如在函数定义里最后return lambda :x*x + y*y
#注意:匿名函数作为返回值返回,等同于return子函数,就是一个闭包函数。

3、#注意:匿名函数有个限制:只能有一个表达式,不用填写return,返回值就是该表达式的结果


四、装饰器@(decorator装饰器 = 高阶函数 + 闭包函数)
装饰器本质上是接受一个函数作为参数(高阶函数行为),并返回一个函数(闭包函数行为)。
返回函数即子函数 中定义添加内容后 再返回主函数的参数函数。
从而实现不修改 参数函数的基础上 在代码运行期间动态增加功能的方式。

1、#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

2、#深入:import functools  
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。
2.1、使用:@functools.wraps(func)
通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。



五、偏函数functools.partial()
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。其中一个就是偏函数(Partial function)。
#偏函数可以通过设定参数的默认值,从而降低函数调用的难度。

1、#使用:functools.partial()用来创建一个偏函数,即把一个函数的某些参数给固定住(即设置默认值),返回一个新函数。
2、#注意:偏函数实质上是一个 @装饰器 的原理,即在参数列表里追加进去 设置默认值的参数。
#如:int2('1000') 实则是运行的 int('1000',base=2)


'''




'''
函数式编程就是一种抽象程度很高的编程范式。

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。
函数就是面向过程的程序设计的基本单元。

纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。
而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python允许使用变量,因此,Python不是纯函数式编程语言。
'''

#################### 高阶函数
#高阶函数
#高阶函数就是一个函数就可以接收另一个函数作为参数的函数。
#一个函数就可以接收另一个函数作为 参数,这种函数就称之为高阶函数。
def add(x,y,fun):
    return fun(x)+fun(y)
print(add(-5,6,abs))


##########
#使用 map(func,*iterables) 将参数func函数 作用于 参数*iterables里的每一个内容,返回一个可迭代对象。
#注意 map(,)函数返回的是一个迭代器iterato,可迭代对象,需要list获取序列化才能输出。

help(map)
type(map)

def f(x):
    return x*x
r=map(f,[1,2,3,4,5,6,7,8,9])
print(list(r))               #注意 map(,)函数返回的是一个可迭代对象,需要list获取序列化才能输出。

#通过map(,)函数将int内容批量转换成str内容
list(map(str,[1,2,3,4,5,6,7,8,9]))


##########
#使用 reduce(func,*iterables,initial) 将参数func函数 作用于 参数序列上,并把结果继续和序列的下一个元素做累计计算。并最终返回值。
#注意 reduce(,) 直接返回累计作用的值。
#参数: func指定参数,iterables指定作用序列,initial指定初始化的序列值。
#注意:如果传入了 initial 参数值, 那么首先传的就不是 iterables 的第一个和第二个元素,而是 initial值 和 iterables的第一个元素

from functools import reduce
help(reduce)

def add(x,y):
    return x+y
reduce(add,[1,3,5,7,9])    #注意 reduce(,)函数返回一个累计后的值。

#####
#示例1:
#如果考虑到字符串str也是一个序列,可作为reduce的参数2,则配合map(),就可以写出把str转换为int的函数
from functools import reduce

def fn(x,y):
    return x*10 + y
def char2num(s):
    digits={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
    return digits[s]       #注意参数s需要是一个str类型 来 对应字典的键明key

print(reduce(fn,map(char2num,'13579')))  #将字符串'13579'作为一个可迭代的类型参数。

#####
#示例2
#使用匿名函数lambda来简写示例1
from functools import reduce
DIGITS={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}

def char2num(s):
    return DIGITS[s]

def str2int(s):
    return reduce(lambda x,y: x*10 + y, map(char2num,s))

str2int('12580')


##########
#使用 filter(func,iters) 过滤序列序列。用参数func函数 过滤 参数iters序列,为True则留下,为False则丢弃。 
#注意 filter(,)返回一个迭代器iterator,需要序列化才能输出。

#和map()类似,filter()也接收一个函数和一个序列。
#不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

help(filter)

#示例在一个list中,删掉偶数,值保留奇数:
def is_odd(n):
    return n%2 == 1    #符号 %求余,//取整。
print(list(filter(is_odd,[1,2,3,4,6,7,8,9])))

#示例把一个序列中的空字符串删掉:
def not_empty(s):
    return s and s.strip()    #.strip()方法用于移除字符串头尾指定的字符(默认移除空格或换行符,注意只能删除开头和结尾)
print(list(filter(not_empty,['A','','B',None,'c','  '])))


#####
#示例用fielter求素数。(素数:一个正整数,如果只有1和它本身两个因数,则叫做素数,也叫做质数。)

#计算素数的一个方法是埃氏筛法,它的算法理解起来非常简单:
#首先,列出从2开始的所有自然数,构造一个序列:2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取新序列的第一个数5,然后用5把序列的5的倍数筛掉:7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#不断筛下去,就可以得到所有的素数。

def _odd_iter():
    """先构造一个从3开始的奇数序列,
    注意 这是一个生成器,并且是一个无限序列的生成器。
    """
    n=1
    while True:
        n=n+2
        yield n

def _not_divisible(n):
    """然后定义一个筛选函数"""
    return lambda x: x%n > 0

def prines():
    """最后定义一个生成器,不断返回下一个素数
    这个生成器先返回第一个素数2,然后,利用filter()过滤函数不断产生筛选后的新的序列
    """
    yield 2
    it=_odd_iter()                          #初始化序列
    while True:
        n=next(it)
        yield n
        it= filter(_not_divisible(n),it)    #构造新序列

"""由于prines()也是一个无限序列,所有调用时需要设置一个退出循环的条件"""
for n in prines():
    if n<1000:
        print(n)
    else:
        break

#生成器 yield
#包含yield的语句被称为 生成器。
#包含 基线条件 和 递归条件。  即最后一个条件处理 和 循环的条件处理。
a=_odd_iter()
print(a)
next(a)


##########
#使用 sorted(iterable, key=None, reverse=False) 对参数iterable序列list进行排序,
#注意 参数key可用来接收一个函数来实现自定义的排序。
#注意 参数reverse为True则反向排序

#示例 按绝对值大小排序
"""key参数指定的函数将作用于每一个元素上,并根据key函数返回的结果进行排序"""
sorted([36,5,-12,9,-21],key=abs)
sorted([36,5,-12,9,-21],key=abs,reverse=True)

help(sorted)




#################### 闭包函数(返回函数)
#使用 闭包函数
#高阶函数除了可以接受函数作为参数外,还可以把函数作为 结果值返回。
#闭包 即在 外部函数中 又定义了 内部函数,并且,内部函数 可以引用 外部函数 的参数和局部变量。
#当 外部函数 返回 内部函数 时,相关参数和变量都保存在返回的函数中,这种闭包程序结构拥有极大的威力,称谓“闭包”。
#参考网址:https://blog.csdn.net/sc_lilei/article/details/80464645


#注意:闭包函数中的return返回内容指向(return返回子函数名称 而不是调用函数)、函数作用域。

#注意:闭包时牢记一点:返回函数(子函数、内部函数)不要引用任何循环变量,或者后续会发生变化的变量。
#如果子函数一定要引用循环变量,方法是再创建一个函数。
#用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

#使用:通过获取主函数的魔法属性__closure__返回的值来确定主函数是否存在闭包。
#__closure__属性返回一个元组对象,包含了闭包引用的外部变量。
#对闭包主函数的__closure__属性迭代后通过cell_contents来输出闭包引用的外部变量
#如果主函数 没有return子函数,就不存在闭包,主函数不存在_closure__属性,返回None
#如果主函数 return的子函数不引用外部变量,也就不存在闭包,主函数的__closure__属性同样返回None。 


#一个可变参数的求和函数
def calc_sum(*args):
    """该函数 立刻返回求和的结果ax"""
    ax=0
    for n in args:
        ax=ax+n
    return ax

#一个返回求和函数名的函数
def lazy_sum(*args):
    """该函数 返回一个函数名(不带括号表示不运行函数),不立即求和,而是等到调用函数()时再进行求和;
    闭包:
    #闭包 即在 外部函数中 又定义了 内部函数,并且,内部函数 可以引用 外部函数 的参数和局部变量。
    #当 外部函数 返回 内部函数 时,相关参数和变量都保存在返回的函数中,这种闭包程序结构拥有极大的威力,称谓“闭包”。

    """
    def sum():
        ax=0
        for n in args:
            ax=ax+n
        return ax
    """ 闭包return返回了子函数名,不是调用子函数()"""
    return sum    #注意这里是返回的 函数名,不带括号表示不运行函数。
f=lazy_sum(1,3,5,7,9)    #相当于赋值给f,赋值内容为 主函数内return返回的子函数名
f()    #这里才是进行了 主函数内return返回的子函数的调用,即立即求和计算结果。


#注意:闭包时牢记一点:返回函数(子函数、内部函数)不要引用任何循环变量,或者后续会发生变化的变量。
def count():
    fs=[]
    for i in range(1,4):
        def f():
            """
            #注意:闭包时牢记一点:返回函数(子函数、内部函数)不要引用任何循环变量,或者后续会发生变化的变量。
            #如果子函数一定要引用循环变量,方法是再创建一个函数。
            #用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
            
            如下内容即引用了循环变量,导致实例化后输出结果都为9
            """
            return i*i 
        
        '''for循环,追加 函数名 进 fs空列表'''
        fs.append(f)
    return fs
f1,f2,f3=count()    #等于 f1,f2,f3=[f, f, f]
f1()                #等于运行 f() 实质子函数f()里i已经运行完毕为最后的 3 。
f2()                #等于运行 f() 实质子函数f()里i已经运行完毕为最后的 3 。
f3()                #等于运行 f() 实质子函数f()里i已经运行完毕为最后的 3 。

#注意:闭包时牢记一点:返回函数(子函数、内部函数)不要引用任何循环变量,或者后续会发生变化的变量。
#如果子函数一定要引用循环变量,方法是再创建一个函数。
#用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
def count():
    def f(j):
        def g():
            return j*j
        return g
    """一个空列表fs,接下来准备append追加进如内容:内容为 函数名带绑定后的参数i 即 f(1)、f(2)、f(3)"""
    fs=[]
    for i in range(1,4):
        fs.append(f(i))
    return fs
f1,f2,f3=count()    #这里实质是列表多重赋值,等于 f1,f2,f3=[f(1),f(2),f(3)]
f1()
f2()
f3()
count()


#继续加深对闭包的理解
_list = []
for i in range(3):
    def func():
        return i+1
    func.__num__= i
    """ 这里实则添加完毕以后的 _list内容为[func,func,func],但是每一个func的__num__不同"""
    _list.append(func)
for f in _list:
    print(f.__num__,
          f()
          )
#实际输出
#0 3
#1 3
#2 3


#通过主函数的参数判断 来return指定子函数。
def get_math_func(type) :
    # 定义一个计算平方的局部函数
    def square(n) :
        return n * n
    # 定义一个计算立方的局部函数
    def cube(n) :
        return n * n * n
    # 定义一个计算阶乘的局部函数
    def factorial(n) :
        result = 1
        for index in range(2 , n + 1):
            result *= index
        return result
    # 返回局部函数
    if type == "square" :
        return square
    if type == "cube" :
        return cube
    else:
        return factorial
# 调用get_math_func(),程序返回一个嵌套函数
math_func = get_math_func("cube") # 得到cube函数
print(math_func(5)) # 输出125

math_func = get_math_func("square") # 得到square函数
print(math_func(5)) # 输出25

math_func = get_math_func("other") # 得到factorial函数
print(math_func(5)) # 输出120


##########
#使用:通过获取主函数的魔法属性__closure__返回的值来确定主函数是否存在闭包。
#__closure__属性返回一个元组对象,包含了闭包引用的外部变量。
#对闭包主函数的__closure__属性迭代后通过cell_contents来输出闭包引用的外部变量
#如果主函数 没有return子函数,就不存在闭包,主函数不存在_closure__属性,返回None
#如果主函数 return的子函数不引用外部变量,也就不存在闭包,主函数的__closure__属性同样返回None。 

# NO.1
def line_conf1(a, b):
    def line(x):
        return a * x + b
    return line
# NO.2
def line_conf2():
    a = 1
    b = 2
 
    def line(x):
        print(a * x + b)
    return line
# NO.3
def _line_(a,b):
    def line_c(c):
        def line(x):
            return a*(x**2)+b*x+c
        return line
    return line_c

L=line_conf2()
print(line_conf2().__closure__)      #通过获取主函数的魔法属性__closure__返回的值来确定主函数是否存在闭包。

for i in line_conf2().__closure__:
    print(i.cell_contents)           #对闭包主函数的__closure__属性迭代后通过cell_contents来输出闭包引用的外部变量


#####
#闭包的实际应用1
def who(name):
    def do(what):
        print(name,'say:',what)
    return do

lucy=who('lucy')
lucy('I want drink!')


#####
#闭包的实际应用
#闭包实现快速给不同项目记录日志:

import logging

def log_header(logger_name):
    """ """
    logging.basicConfig(level=logging.DEBUG, 
                        format='%(asctime)s [%(name)s] %(levelname)s  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')
    logger = logging.getLogger(logger_name)
 
    
    def _logging(something,level):
        """ 返回的数(子函数),通过判断参数2 来调用日志输出类型,输出内容为参数1 """
        if level == 'debug':
            logger.debug(something)
        elif level == 'warning':
            logger.warning(something)
        elif level == 'error':
            logger.error(something)
        else:
            """ 如果没有传入参数2日志级别,则手动引发异常"""
            raise Exception("I dont know what you want to do?" )
    return _logging
 
project_1_logging = log_header('project_1')
project_2_logging = log_header('project_2')
 

def project_1():
    #多此一举加函数
    project_1_logging('this is a debug info','debug')
    project_1_logging('this is a warning info','warning')
    project_1_logging('this is a error info','error')
 
def project_2():
    #多此一举加函数
    project_2_logging('this is a debug info','debug')
    project_2_logging('this is a warning info','warning')
    project_2_logging('this is a critical info','error')
 
project_1()
project_2()




#################### 匿名函数
#关键字lambdab表示匿名函数,lambda x : x*x,冒号前面表示函数参数,冒号后面表达式表示函数内容
#使用:匿名函数可以赋值变量,lambda也是一个函数对象,也可以赋值给变量,然后通过变量来调用匿名函数。

#使用:匿名函数可以赋值变量,lambda也是一个函数对象,也可以赋值给变量,然后通过变量来调用匿名函数。

#使用:匿名函数可以作为返回值返回,如在函数定义里最后return lambda :x*x + y*y
#注意:匿名函数作为返回值返回,等同于return子函数,就是一个闭包函数。

#注意:匿名函数有个限制:只能有一个表达式,不用填写return,返回值就是该表达式的结果



#可以使用 lambda匿名函数 结合 map高阶函数 来计算乘方
list(map(lambda x: x*x,[1,2,3,4,5,6,7,8,9]))

#使用:匿名函数可以赋值变量,lambda也是一个函数对象,也可以赋值给变量,然后通过变量来调用匿名函数。
f=lambda x: x*x
f(5)
f

#使用:匿名函数作为返回值返回,如在函数定义里最后return lambda :x*x + y*y
#注意:匿名函数作为返回值返回,等同于return子函数,就是一个闭包函数。 
def build(x,y):
    """ 匿名函数作为返回值返回,等同于return子函数,就是一个闭包函数
    注意:闭包函数注意 return的返回指向是否存在()的调用形式"""
    return lambda :x*x + y*y
b=build(5,10)
b()

#可以使用lambda匿名函数 结合 map高阶函数 来过滤偶数
list(filter(lambda n: n%2==1,range(1,21)))




################### 装饰器@(decorator装饰器 = 高阶函数 + 闭包函数)
#装饰器本质上是接受一个函数作为参数(高阶函数行为),并返回一个函数(闭包函数行为)。
#返回函数即子函数 中定义添加内容后 再返回主函数的参数函数。
#从而实现不修改 参数函数的基础上 在代码运行期间动态增加功能的方式。

#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。
#深入:import functools  使用:@functools.wraps(func)


#####
#定义一个本身不需要传入参数的装饰器 打印日志的装饰器decorator
def log(func):
    """接收一个函数作为参数,称为高阶函数
    返回子函数,称为闭包函数"""
    def wrapper(*args,**kw):
        """返回主函数的参数函数,从而达到不修改参数函数的基础上 动态增加print功能"""
        print('开始调用函数:%s()' %func.__name__)
        """动态增加print功能后,继续调用原函数()执行"""
        return func(*args,**kw)
    return wrapper
"""使用:@decorator放到 func函数定义前,相当于执行了 func=decorator(func),重新赋值定义了一个同名新函数"""
@log    
def now():
    print('2019/11/08')
now()
"""等同于不添加装饰器@log情况下的如下表示:"""
#log(now)()
#now=log(now)
#now()


#####
#定义一个本身需要传入参数的装饰 打印日志的装饰器
#使用:如果装饰器decorator本身需要传入参数,那就需要编写一个返回装饰器的高阶函数(即三层嵌套装饰器函数)。
def log(who):
    def decorator(func):
        def wrapper(*args,**kw):
            print('%s开始调用函数:%s()' %(who,func.__name__))
            return func(*args,**kw)
        return wrapper
    return decorator
@log('小王')
def now():
    print('2019/11/09')
now()
"""等同于不添加#log('小王')的如下表示:"""
#log('小张')(now)()
#now=log('小张')(now)
#now()



#####
#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

#深入:import functools  
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。
#2.1、使用:@functools.wraps(func)
#通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

import functools

def log(func):
#    @functools.wraps(func)
    def wrapper(*args,**kw):
        print('开始调用函数:%s()' %func.__name__)
        return func(*args,**kw)
    return wrapper
@log
def now():
    print('2019/11/09')
now()
print(now.__name__)

#对比添加了 @functools.wraps(func) 装饰器之后的 now.__name__

import functools

def log(who):
    def decorator(func):
        """使用:functools.wraps(func)装饰器
        通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 
        来纠正被此装饰器装饰过的func函数属性。
        """
        @functools.wraps(func)
        def wrapper(*args,**kw):
            print('%s \n %s开始调用函数:%s' %('接下来使用了functools.wraps(func)技术',who,func.__name__))
            return func(*args,**kw)
        return wrapper
    return decorator
@log('小刘')
def now():
    print('2019/11/10')
now()
now.__name__




#################### 偏函数functools.partial()
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。其中一个就是偏函数(Partial function)。
#偏函数可以通过设定参数的默认值,从而降低函数调用的难度。

#使用:functools.partial()用来创建一个偏函数,即把一个函数的某些参数给固定住(即设置默认值),返回一个新函数。
#注意:偏函数实质上是一个 @装饰器 的原理,即在参数列表里追加进去 设置默认值的参数。
#如:int2('1000') 实则是运行的 int('1000',base=2)


#修改int()函数的默认base参数,来达到 N进制的转换。
int('1000', base=8)    #八进制:十位数上表示*8、百位数上表示64(8*8)、千位数上表示512(8*8*8)
int('10000',base=2)     #二进制:十位数上表示*2、百位数上表示4(2*2)、千位数上表示8(2*2*2)


#使用:functools.partial()用来创建一个偏函数,即把一个函数的某些参数给固定住(即设置默认值),返回一个新函数。
import functools

int2=functools.partial(int,base=2)
int2('1000')

#注意:偏函数实质上是一个 @装饰器 的原理,即在参数列表里追加进去 设置默认值的参数。
#如:int2('1000') 实则是运行的 int('1000',base=2)

max2=functools.partial(max,10)
max2(2,5,9)    #max2(2,5,9) 实则是运行的max(2,5,9,10)

















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值