python 函数篇 —— 作用域、参数类型、装饰器、高阶函数

2021/5/21 22:24:49

本文主要是介绍python 函数篇 —— 作用域、参数类型、装饰器、高阶函数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 函数
    • 变量和作用域
    • 函数的参数
    • 解压可迭代对象赋值给多个变量
  • 装饰器
  • 所需掌握的函数
    • lambda
    • map
    • reduce
    • filter
    • sorted
    • enumerate
    • zip

函数

变量和作用域

使用函数的两个小习惯:

  1. 当要定义的函数比较复杂时,可以对函数的参数和返回值进行注释,注释内容可以是任何形式(参数的类型、作用、取值范围等),如下面代码中的(n:int)和( ->list),当然注释只是方便阅读代码,对程序的执行没有影响;
  2. 函数体中使用文档声明,描述函数的相关信息;
def fib(n:int)->list:
    """返回一个包含斐波那契数列的列表"""

    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b

    return result

# 使用 fib.__annotations__ 可以查看注释

关于变量和作用域:

# encoding: utf-8
a = 1               # 全局作用域的变量 a
def fn():
    a = 2           # 嵌套作用域的变量 a
    def inner_fn():
        a = 3       # 当前作用域的变量 a

# 上述代码只是方便叙述知识点

搜索变量的顺序是由内到外:

当前作用域变量 -> 嵌套作用域变量 -> 全局变量 -> python内置变量

globalnonlocal 关键字的区别:

  • 在当前作用域下想操作嵌套作用域的变量,使用 nonlocal;
  • 在当前作用域下想操作全局变量,使用 global。
# encoding: utf-8
a = 1               # 全局作用域的变量 a
def fn():
    a = 2           # 嵌套作用域的变量 a
    print('嵌套作用域变量a=', a)

    def inner_fn():
        nonlocal a      # global a
        a = 3       # 当前作用域的变量 a

    inner_fn()      # 这条语句若放在 inner_fn() 定义之前,会报错
    print('嵌套作用域变量a=', a)

print('全局变量a=', a)
fn()
print('全局变量a=', a)

函数的参数

参数的形态有:位置参数、默认参数、可变参数、关键字参数、命名关键字参数

可变参数(*arg):传入的参数个数可以是 0个到任意个;可变参数在函数调用时自动组装为一个tuple;

def fn(name, *phone_numbers):
    print('name:{}  phtoe_numbers:{}'.format(name,phone_numbers))

fn('Stack')
# name:Stack  phtoe_numbers:()
fn('Thor', 110, 119, 120)
# name:Thor  phtoe_numbers:(110, 119, 120)

关键字参数(**kw):允许传入 0个到任意个 带参数名的参数;关键字参数在函数内部自动组装为一个dict;

def fn(name, **kw):
    print('name:{}  orther:{}'.format(name, kw))

fn('Stack')
name:Stack  orther:{}
fn('Thor', job='thunder god', age=1500)
name:Thor  orther:{'job': 'thunder god', 'age': 1500}

命名关键字参数(args,*,args):用来限制关键字参数的参数名;

'''注意查看 TypeError'''
def fn(name, *, job, sex):
    print('name:{}  orther:{}'.format(name, kw))

fn('Stack')
# TypeError: fn() missing 2 required keyword-only arguments: 'job' and 'sex'
fn('Thor', job='thunder god', age=1500)
# TypeError: fn() got an unexpected keyword argument 'age'

组合参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

解压可迭代对象赋值给多个变量

  • 使用 * 运算符从列表或元组中解包参数:
arr = [1, 2, 3, 4, 5]
a, *b, c = arr
print('a={}, b={}, c={}'.format(a,b,c))
# a=1, b=[2, 3, 4], c=5

*a, b, c = arr
print('a={}, b={}, c={}'.format(a,b,c))
# a=[1, 2, 3], b=4, c=5

这种解压语法通常用在具有特殊元素结构的可迭代对象上,如:

person = ['Tony Stack', 'Male', 'IronMan@gmail.com','IronMan@163.com','IronMan@qq.com']
name, sex, *email = person
print('email = ', email)
# email =  ['IronMan@gmail.com', 'IronMan@163.com', 'IronMan@qq.com']

装饰器

装饰器就是用于拓展函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

一个通俗的例子:

def working_hours(hours):
    '''打印工作时长'''
    print("Today's working_hours : ", hours)

现在要求在不改动函数代码的情况下增加新的功能:根据工时判断加班还是下班;

def working_overtime(func):
    def wrapper(hours):
        func(hours)     # 这条语句执行原函数功能,下面的条件语句是新增功能
        if int(hours) < 8:
            print('You have to keep working')
        else:
            print('Off work')
    return wrapper      # working_Overtime函数的返回值必须是一个函数

@working_overtime       # 相当于执行了 working_hours = working_overtime(working_hors)
def working_hours(hours):
    print("Today's working_hours : ", hours)

working_hours(7)
working_hours(9)

# 输出结果
Today's working_hours :  7
You have to keep working
Today's working_hours :  9
Off work

通过@working_overtime这条语句为原函数添加了一个装饰器,它相当于执行了 working_hours = working_overtime(working_hors)

以内层函数wrapper为标志,它内部的代码是核心区,是为原函数working_hours添加的新功能,原函数所需的参数可以同通过wrapper函数传递,wrapper函数可以没有返回值;

外层函数working_overtime相当于是传递原函数的接口,它和内层函数wrapper之间的部分可以有其它代码,不过这些代码不会被装饰到原函数上的,而是在装载装饰器时的附加操作

注意装饰器的返回值一定是一个函数。

def working_overtime(func):
    print('此区域没有被装饰到原函数,无论原函数运行多少次,它只运行一次')
    def wrapper(hours):
        ...省略...
    return wrapper

@working_overtime
def working_hours(hours):
    print("Today's working_hours : ", hours)

working_hours(7)
working_hours(9)

# 输出结果
此区域没有被装饰到原函数,无论原函数运行多少次,它只运行一次
Today's working_hours :  7
You have to keep working
Today's working_hours :  9
Off work

当原函数参数较多时,装饰器可以使用*args, **kw的参数形式:

def deco(func):
    ...
    def wrapper(*args, **kw):
        ...
    returen wrapper
    
@deco
def myfunc(*args, **kw):
    ...

还有一种带参数的装饰器:

def daily_salary(hourly_salary):
    '''新增计算日薪的功能'''
    def working_overtime(func):
        def wrapper(hours):
            func(hours)
            print('salary = ',hourly_salary * hours)
        return wrapper
    return working_overtime

@daily_salary(40)
def working_hours(hours):
    print("Today's working_hours : ", hours)

working_hours(7)
working_hours(9)

# 输出结果
Today's working_hours :  7
salary =  280
Today's working_hours :  9
salary =  360

值得一提的是,当某个函数有多个装饰器时,执行的顺序是:从下面的装饰器开始往上依次执行,最后执行原函数本身。

所需掌握的函数

Python 内置函数大全

lambda

使用 lambda 关键字可以创建一个匿名函数(通俗地说就是没有名字的函数),lambda函数可以在需要函数对象的任何地方使用。

语法形式:

 lambda argument_list: expression

arhument_list 是参数列表,可以有多种形式;expression 是关于参数的表达式,表达式只能是单行的

lambda 函数最常用的用法是将其作为参数传递给其它函数。

map

map(func, *iterables) --> map object
    """
    Make an iterator that computes the function using arguments from
    each of the iterables.  Stops when the shortest iterable is exhausted.
    """

参数 func 是一个函数(func可以拥有多个参数),参数 iterable 是可迭代对象(iterable的个数对应func参数的个数);

map 函数将传入的函数依次作用到 iterables 的每个元素,并把结果作为新的 Iterator 返回。

# func 只有一个参数时,iterable 也只有一个
map(lambda x : x*x, [1,2,3,4,5]
# [1, 4, 9, 16, 25]

# func 拥有多个参数时,iterable 拥有对应的个数
map(lambda x, y, z: x+y+z, [1,2],(3,4,5),[6,7,8,9])
# [10, 13]

reduce

reduce(function, sequence, initial=_initial_missing):
    """
    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.
    """

# 源代码中有下面两条有语句,要求 function 有两个参数
    for element in it:
        value = function(value, element)

参数 function 是带有两个参数的函数 ,sequence 是可迭代对象;

reduce 函数将 function 从左至右累加的应用到 iterable 中的每个元素,最终返回一个累加值。

from functools import reduce
print(reduce(lambda x, y : 10*x + y, [1,2,3,0,6]))
# 12306

filter

filter(function or None, iterable) --> filter object
    """
    Return an iterator yielding those items of iterable for which function(item)
    is true. If function is None, return the items that are true.
    """

filter 函数把传入的函数依次作用于每个元素,根据返回值是 True 还是 False 决定保留还是丢弃该元素。

# function 是 None 时,iterable 会筛选一遍非空元素
filter(None, [666, 'a', '', -1, 'False', False, [],[0,'b',False]])
# [666, 'a', -1, 'False', [0, 'b', False]]

# 筛选10以内的偶数
filter(lambda x : x%2 == 0, range(11))
# [0, 2, 4, 6, 8, 10]

sorted

sorted(iterable, *, key=None, reverse=False)

sorted 函数会将 iterable 里的元素进行排序;有两个可选参数 key 和 reverse,参数 key 指定一个函数(相当于排序依据),reverse 指定正序或逆序。

sorted([3, -5, 7, 0])
# [-5, 0, 3, 7]

sorted([3, -5, 7, 0], key=abs, reverse=True)
# [7, -5, 3, 0]

enumerate

enumerate(iterable, start=0)
     """
    The enumerate object yields pairs containing a count (from start, which
    defaults to zero) and a value yielded by the iterable argument.
    
    enumerate is useful for obtaining an indexed list:
        (0, seq[0]), (1, seq[1]), (2, seq[2]), ...
    """

enumerate 函数返回一个枚举对象,它的作用就是给 iterable 对象中的元素添加一个计数值,默认从o开始计数(若没有指定start)。

seasons = ['Spring', 'Summer', 'Fall', 'Winter']
print(list(enumerate(seasons)))

# [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

enumerate 函数等价于:

def enumerate(sequence, start=0):
    n = start
    for elem in sequence:
        yield n, elem
        n += 1

zip

zip(*iterables)
    """
    return a zip object yielding tuples until an input is exhausted.
       >>> list(zip('abcdefg', range(3), range(4)))
       [('a', 0, 0), ('b', 1, 1), ('c', 2, 2)]
    """

返回一个元组的迭代器,其中的第 i 个元组包含来自每个参数序列或可迭代对象的第 i 个元素。 当所输入可迭代对象中最短的一个被耗尽时,迭代器将停止迭代。 当只有一个可迭代对象参数时,它将返回一个单元组的迭代器。 不带参数时,它将返回一个空迭代器。



这篇关于python 函数篇 —— 作用域、参数类型、装饰器、高阶函数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程