Python 函数

1. 概念理解

1.1 定义

  • 执行特定任务, 完成特定功能的一段代码.

1.2 作用

  • 复用
  • 隐藏实现细节
  • 提高可维护性

1.3 基本形式

def fname([parameters]):
    code
    [return variable/expression]

fname(arguments)

def dao(x, y):
    z = x + y
    return z
dao(1, 2)

2. 函数参数

Python 函数的参数有很多变化, 主要从以下三个方面来阐述.

  1. 按顺序(位置), 还是按指定的参数名称传递和调用?
  2. 参数的默认值
  3. 参数的数量

2.1 形参

是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传递的参数。

2.2 位置参数

dao(10 , 20)

2.3 关键词参数

dao(a = 10, b = 20)

 

2.4 默认参数

在形参中设置默认值, 调用函数传入实参时如果不传入参数, 则使用默认值; 如传入参数则使用实参.

def dao(a, b, c=100): # 含有默认值的参数, 必须置于不含默认值参数的后面.
    print(a, b , c)
dao(86, 32)  # 此处调用函数时, 并未传入第三个实参, 但因为在形参中给其设置了默认值, 故运行时会自动使用默认值.

 

2.5 参数传递

2.6 可变形参

2.6.1 数量可变的顺序参数

def dao(*args):
    print(args)
dao(10, 20)

2.6.2 数量可变的关键字参数

def dao(**args):
    print(args)
dao(a = 10, b = 20)

2.7 实参

2.8 可变实参

def dao(a, b, c):
    print(a, b , c)

dict = {
'a' : 1,
'b' : 2,
'c' : 3,
}
dao(**dict)

 

3. return

 

4. 闭包函数

4.1 概念理解

为什么会有闭包? 出于各种原因,有时候需要在函数外部访问函数内的数据。但由于Python中作用域的约束, 子对象会一级一级地向上寻找所有父对象的变量,就导致这一点通常是无法实现的。

def outer():
v =100;

print(v)

很显然此时, 程序会报错: NameError: name ‘v’ is not defined. 在函数外部, 无法调用函数内部的变量v.

所以问题来了, 如果想在函数外部访问函数内部的数据, 该怎么做?

def outer(a):  # 定义外部函数
    b = 10  # 定义一个外部函数的变量b

    def inner():  # 定义内部函数
        return a + b  # 为内部函数添加简单的功能, 并用return返回.

    return inner  # 外部函数被调用后, 返回内部函数. (这里是突破函数作用域约束, 让内外函数进行沟通得关键之处.)

outer(9)()  # 如所期望的, 输出结果19, 这表明outer函数内部的变量b, 在它的外面被访问到了.

那么此时, 内部函数, 即被称为 “闭包”.


 

 

4.2 简单总结

  • 闭包是一个函数
  • 闭包函数是由其他代码生成的
  • 闭包函数携带了生成环境的信息
  • 闭包可以让一个变量常驻内存
  • 闭包可以避免变量被修改

5. 装饰器

5.1 定义

  • 装饰器本质上是一个函数,用来对另一个函数(被装饰的函数对象)在不改动代码的前提下做功能上的补充, 如增加身份或权限验证、插入日志等。
  • 装饰器以被装饰的函数对象为输入参数,返回一个新的对象。
  • 装饰器的概念本身不难理解,可能令初学者最感到困惑的是,如何在装饰器函数和被装饰的函数对象之间建立联系。

5.2 实例

我们想象这样一个情景:

  1. 你喜欢玩LOL和TOC.
  2. 可技不如人, 抑或运气不佳, 联盟总输, 云顶总第八,  于是想到外挂.
  3. 这样一来, 游戏体验大幅上升, 但还剩最后一个”不是问题的问题”.
  4. 每次打开游戏前, 需要先打开外观. 游戏结束后, 需要关闭外挂 — 这对于任性有钱的你而言, 很麻烦.
  5. 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.

 

 

# 1. 你喜欢玩LOL和TOC.
def play_lol():
    print("玩英雄联盟")

def play_toc():
    print("玩云顶之弈")

 

# 2/3/4  每次打开游戏前, 需要先打开外观. 游戏结束后, 需要关闭外挂 -- 这对于任性有钱的你而言, 很麻烦.
def play_lol():
    print("玩英雄联盟")

def play_toc():
    print("玩云顶之弈")


print("打开外挂")
play_lol()
print("关闭外挂") 

print("打开外挂")
play_toc()
print("关闭外挂")
# 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.
def assistant(game):
    def inner():
        print("打开外挂")
        game()
        print("关闭外挂")
    return inner

def play_lol():
    print("玩英雄联盟")

def play_toc():
    print("玩云顶之弈")
    
    
assistant(play_lol)()
assistant(play_toc)()

 

# 所以你打算聘请一个无所不能的, 智能的秘书, 她总能在你想玩游戏的3分钟前, 替你打开外挂.2
# 为了便于理解, 这里做了一个小调整, 将函数assistant(play_lol)赋值给变量, 使用时调用变量即可.
def assistant(game):
    def inner():
        print("打开外挂")
        game()
        print("关闭外挂")
    return inner

def play_lol():
    print("玩英雄联盟")

def play_toc():
    print("玩云顶之弈")
    
    
play_lol = assistant(play_lol)
play_toc = assistant(play_toc)

play_lol()
play_toc()

5.2.1 执行流程

  • 假设现在想玩LOL, 那么调用函数assistant(play_lol)
  • 进入到assistant(play_lol)内部的功能代码
  • assistant(play_lol)的返回结果是 return inner
  • assistant(play_lol)()即是inner()
  • 执行inner函数
    • 开外挂
    • 玩游戏 play_lol()
    • 关外挂

5.3 装饰器的雏形

def assistant(game):
    def inner():
        print("打开外挂")
        game()
        print("关闭外挂")
    return inner


@assistant
def play_lol():
    print("玩英雄联盟")

@assistant
def play_toc():
    print("玩云顶之弈")
    
    
# play_lol = assistant(play_lol)  相当于 @assistant
# play_toc = assistant(play_toc)  相当于 @assistant

play_lol()
play_toc()

5.4 带参数的装饰器

  • 需求升级: 玩游戏, 开外挂, 需要账号和密码, 玩英雄联盟时, 还需要设置想玩的英雄.
def assistant(game):
    def inner(*args, **kwargs):   #不定形参
        print("打开外挂")
        game(*args, **kwargs)
        print("关闭外挂")
    return inner


@assistant
def play_lol(username, password, champion):
    print("玩英雄联盟")
    print(username, password, champion)
    

@assistant
def play_toc(username, password):
    print("玩云顶之弈")
    print(username, password)
    
    
# play_lol = assistant(play_lol)
# play_toc = assistant(play_toc)

play_lol("jin", "123456", "kasha")
play_toc("xin", "123456")

 

 

5.4.1 参数调用说明

在形参中:
*args 传递可变的顺序参数给实参, 其形式是元组
**kwargs 传递可变的关键字参数给函数实参, 其形式是列表

在实参中:
*args 将元组形式的形参, 解散成字符串
**kwargs 将列表形式的形参, 解散成字符串

 

5.5 带 返回值的装饰器

 

5.6 装饰器总结

  • 从代码可以看出,  函数里的play_lol = assistant(play_lol) 相当于 装饰器里的@assistant, 所以装饰器实际上是一种语法糖, 不使用装饰器, 也一样可以实现.
  •  装饰器本质是一个闭包, 即外部函数调用内部函数数据, 在不改动代码的前提下做功能上的补充.
  • 装饰器的用途: 比如想统计某段代码执行所需的时间, 那么可以在其前后调用装饰器.

本站文章除单独注明外均为原创,本文链接https://bowmanjin.com/137,未经允许请勿转载。

0

评论0

请先

没有账号? 注册  忘记密码?