• 【python3的学习之路九】函数式编程


    变量作用域

    变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:

    • L (Local) 局部作用域
    • E (Enclosing) 闭包函数外的函数中
    • G (Global) 全局作用域
    • B (Built-in) 内建作用域

    以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

    x = int(2.9)  # 内建作用域
     
    g_count = 0  # 全局作用域
    def outer():
        o_count = 1  # 闭包函数外的函数中
        def inner():
            i_count = 2  # 局部作用域

    global和nonlocal关键字

    当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字。

    num = 1
    def fun1():
        global num  # 需要使用 global 关键字声明
        print(num) 
        num = 123
        print(num)
    fun1()
    print(num)

    如果要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量nonlocal关键字,如下:

    def outer():
        num = 10
        def inner():
            nonlocal num   # nonlocal关键字声明
            num = 100
            print(num)
        inner()
        print(num)
    outer()

    传入函数

    变量也可以指向函数,函数的参数能接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数就称之为高阶函数。

    def add(x, y, f):
        print(f(x) + f(y))
    
    add(-5, 6, abs)   # 11
    • map

    map()函数接受俩个参数,一个是函数,一个是Iterator,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator。

    def f(x):
        return x * x
    
    r = map(f, [1, 2, 3, 4, 5])
    print(r)   # [1, 4, 9, 16, 25]
    print(list(map(str, [1, 2, 3, 4, 5])))   # ['1', '2', '3', '4', '5']
    • filter

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

    def is_odd(n):
         return n % 2 == 1
    
    def not_empty(s):
        return s and s.strip()
    
    print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])))     # [1, 5, 9, 15]
    print(list(filter(not_empty, ['A', '', 'b', ' ', 'c', None]))) #['A', 'b', 'c']

    注意:filter()函数转换成list

    练习题:取出1~1000中的回数。回数是指从左向右读和从右向左读都是一样的数,例如12321,909。

    def get(l):
        s = str(l)
        return s == s[::-1]  # 请回顾切片
    
    print(list(filter(get, range(1,1000))))
    • sorted

    sorted()函数可以对list进行排序

    sorted([36, 5, -12, 9, -21])  # [-21, -12, 5, 9, 36]
    sorted([36, 5, -12, 9, -21], key = abs) #[5, 9, -12, -21, 36]
    sorted(['bob', 'about', 'Zoo', 'Credit']) # ['Credit', 'Zoo', 'about', 'bob'] 对字符串排序,是按照ASCII的大小比较的
    sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower) # ['about', 'bob', 'Credit', 'Zoo']
    sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower, reverse = True) # ['Zoo', 'Credit', 'bob', 'about']

    返回函数

    当我们调用c时返回的是求和函数,每次调用都会返回一个新的函数,即使传入相同的参数,所以f1和f2调用的结果互不影响。

    def c(*args):
        def sum():
            ax = 0
            for n in args:
               ax = ax + n
            return ax
        return sum
    
    print(c(1, 3, 4, 5, 6)())
    f1 = c(1, 3, 5, 7, 9)
    f2 = c(1, 3, 5, 7, 9)
    print(f1 == f2)   # False

    匿名函数

    • 关键字lambda表示匿名函数,冒号前面的x表示函数参数。
    • 匿名函数只能有一个表达式,不用写return,返回值就是该表达式的结果
    • 匿名函数没有名字,不必担心函数名冲突
    • 匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
    list(map(lambda x: x * x, [1, 2, 3, 4, 5]))
    # def f(x):
    #     return x * x
    
    def build(x, y):
        return lambda: x * x + y * y

    装饰器

    在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
    我们定义一个能打印日志的decorator——log,它能接受一个函数作为参数,并返回一个函数。调用time()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志。

    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('call %s():' %func.__name__)
            return func(*args, **kwargs)
        return wrapper
    
    @log             # 相当执行语句now = log(now)
    def time():
        print('2015-12-09')

    如果decorator本身需要传入参数、那么需要编写一个返回decorator的高阶函数。比如,要自定义log的文本。

    def log(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                print('%s %s():' %(text, func.__name__))
                return func(*args, **kwargs)
            return wrapper
        return decorator
    
    @log('execute')           # 相当执行语句now = log('execute')(now)
    def time():
        print('2015-12-09')

    因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写 wrapper._ name_ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的。

    偏函数

    通过设定参数的默认值,可以降低函数调用的难度,而偏函数就可以做到这一点。
    假设要转换大量的二进制字符串,每次都传入++int(x, base = 2)++非常麻烦,我们就可以定义一个函数,把默认的base = 2传进去

    def int2(x, base = 2)
        return int(x, base)

    functools.partial就帮助我们创建一个偏函数,不需要我们自定义int2()

    import functools
    int2 = functools.partial(int, base = 2)
  • 相关阅读:
    golang mysql相关操作 Marathon
    golang gin框架使用ShouldBindJson && ShouldBindBodyWith的区别 Marathon
    (三)GORM连接数据库
    [go每日一库]golanggorm实现关联查询(四) Marathon
    [go每日一库]golanggorm实现增删改查CRUD(三) Marathon
    (九)GORM 关联查询属于
    (一)GORM快速入门教程
    [go每日一库]golang Json的编解码 Marathon
    [go每日一库]golang swagger自动生成api文档 Marathon
    golang gin框架中间件的使用使用流程、定义、用例及总结(全面) Marathon
  • 原文地址:https://www.cnblogs.com/CSgarcia/p/9706136.html
Copyright © 2020-2023  润新知