python 头等对象之一,python 函数那些不一般的用法

Posted 梦想橡皮擦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 头等对象之一,python 函数那些不一般的用法相关的知识,希望对你有一定的参考价值。

本篇博客为你带来 python 函数相关知识点的回顾。

函数是 python 语言中一个非常重要的概念,并且是头等对象,可以把函数分配给变量,也可以将其作为参数传递给其它函数,当然作为其它函数的返回值也是可以的。

函数就是对象

函数是对象,所以可以将其赋值给一个变量

def func():
    print("hello 橡皮擦")


my_var = func  # 注意没有括号
my_var()  # 调用

函数是对象,所以可以出现在其它数据结构中,例如列表
函数可以作为列表的项。

def func():
    print("hello 橡皮擦")


my_list = [func, 1, 2, 3]  # 列表第一项是函数
print(my_list)
my_list[0]()  # 列表第一项可以调用

函数是对象,所以可以作为其它函数的参数

def func():
    print("hello 橡皮擦")


def func1(func):
    func()  # 调用参数


func1(func)  # 函数作为参数

可以接受其它函数作为参数的函数,称为高阶函数,这与我们之前学习的函数式编程又产生了关联。

函数是对象,所以可以作为其它函数的返回值

函数作为返回值,又衍生出来一个概念,函数的嵌套(内部函数)

def func():
    def inner_func():
        print("内部函数")

    return inner_func


print(func())  # 输出 <function func.<locals>.inner_func at 0x00000000028581E0>

func()()  # 输出内部函数

如果函数作为返回值,那调用外层函数只能得到一个函数对象,因此会出现 func()() 这样奇怪的写法。

函数的嵌套还衍生一个概念,叫做 词法闭包,一般叫做 闭包,其核心内容是内部函数可以访问父函数中的参数。

def func():
    f_name = "橡皮擦"

    def inner_func():
        print("内部函数")
        print(f_name)

    return inner_func


inner = func()

inner()  # 输出内部函数与橡皮擦

python 中小小的装饰器

学习装饰器的前提是掌握 函数是头等对象

装饰器是用来 包装 函数的,它可以在不修改原函数的前提下,在被包装函数的前后增加代码。

最简单的包装如下,给一个函数增加运行时间。

def func():
    for i in range(100000):
        pass


def time_decorator(func):
    import time
    start_time = time.perf_counter()
    func()
    print(f"{func.__name__} 运行时间为:", time.perf_counter() - start_time)

# 装饰 func 函数
time_decorator(func)

上述代码中 time_decorator 就是一个装饰器,func 函数作为参数传递给它,从而实现代码运行时间的获取。

使用 @函数名 可以更加方便的调用装饰器。

def time_decorator(func):
    import time
    start_time = time.perf_counter()
    func()
    print(f"{func.__name__} 运行时间为:", time.perf_counter() - start_time)


@time_decorator
def func():
    for i in range(100000):
        pass

使用 @ 语言,会立即装饰该函数,如果你想要调用 func() ,此时会出现如下错误:

Traceback (most recent call last):
  File "E:/xxxx/18.py", line 13, in <module>
    func()
TypeError: 'NoneType' object is not callable

如果希望原函数还可以访问,需要在装饰器函数中嵌套内部函数,并将其返回。

def time_decorator(func):
    import time
    # 嵌套函数
    def wrapper():
        start_time = time.perf_counter()
        func()
        print(f"{func.__name__} 运行时间为:", time.perf_counter() - start_time)
    # 返回内部函数
    return wrapper


@time_decorator
def func():
    for i in range(100000):
        pass


func()

一个函数可以被多个装饰器装饰,效果从下到上运行
从下到上理解为接近函数的装饰器先运行。

# 加粗标签装饰器
def b(func):
    def wrapper():
        return f'<b>{func()}</b>'

    return wrapper


# 段落标签装饰器
def p(func):
    def wrapper():
        return f'<p>{func()}</p>'

    return wrapper


@p
@b
def my_func():
    return "橡皮擦"


print(my_func())

装饰器由于词法闭包,会隐藏原函数的名称、文档字符串、参数列表
为了解决该问题,需要导入 functools 模块中的 wraps 函数,先测试一下被装饰器修饰之后的函数相关信息。

def title(func):
    def wrapper():
        """装饰器"""
        return func().title()

    return wrapper


@title
def say():
    return "hello world"


h = say()
print(h)  # 被装饰之后,单词首字母大写。
print(say.__name__)  # 输出其函数名
print(say.__doc__)  # 文档字符串

对应的输出内容如下:

Hello World
wrapper
装饰器

可以发现 say 函数的函数名与文档字符串都已经被修改,如果不希望上述现象产生,使用 functools 模块的 wraps 函数即可。

from functools import wraps
def title(func):
    @wraps(func) # 复制信息到装饰器
    def wrapper():
        """装饰器"""
        return func().title()

    return wrapper


@title
def say():
    """say 函数文档字符串"""
    return "hello world"


h = say()
print(h)  # 被装饰之后,单词首字母大写。
print(say.__name__)  # 输出其函数名
print(say.__doc__)  # 文档字符串

对应输出修改为下述内容:

Hello World
say
say 函数文档字符串

装饰器中的参数
在编写装饰器的时候,经常碰到被装饰的函数具有参数情况,实操过程中使用 python 变长参数 *** 特性,即可解决该问题。
如果函数只有一个参数,直接在 wrapper 声明即可

def title(func):
    @wraps(func)  # 复制信息到装饰器
    def wrapper(name):
        """装饰器"""
        return func(name).title()

    return wrapper


@title
def say(name):
    """say 函数文档字符串"""
    return name + "hello"


h = say("橡皮擦")
print(h)

*多个参数就比较繁琐了,所以位置参数直接使用 *args,关键字参数使用 *kwargs

from functools import wraps


def title(func):
    @wraps(func)  # 复制信息到装饰器
    def wrapper(*args):
        """装饰器"""
        return func(*args).title()

    return wrapper


@title
def say(name, age):
    """say 函数文档字符串"""
    return name + " hello " + " age " + str(age)


h = say("橡皮擦",18)
print(h)

下述代码为关键字参数测试代码:

from functools import wraps


def title(func):
    @wraps(func)  # 复制信息到装饰器
    def wrapper(*args,**kwargs):
        """装饰器"""
        return func(*args,**kwargs).title()

    return wrapper


@title
def say(name):
    """say 函数文档字符串"""
    return name + " hello "


h = say(name="橡皮擦")
print(h)

总结一下:

  • *args:用来收集额外的位置参数,组成元组;
  • **kwargs:用来收集关键字参数,组成字典。

其中 argskwargs 非固定名称,你可以根据需要进行设置,不过行业里面其它程序员都遵守该规范。

写在后面

以上内容就是本文的全部内容,希望对学习路上的你有所帮助~

今天是持续写作的第 236 / 365 天。
期待 关注点赞评论收藏

更多精彩

以上是关于python 头等对象之一,python 函数那些不一般的用法的主要内容,如果未能解决你的问题,请参考以下文章

python 关于函数的语法

前端学习之函数式编程—函数式编程概念+头等函数

Python-面向对象之一

Python 函数式编程,看这一篇就够了!

Python 函数式编程,看这一篇就够了!

Python 函数式编程,看这一篇就够了!