函数_笔记

一、函数

1. 函数定义

​ 1.1 先定义, 后调用

函数定义:

"""
def my_fun():  # my_fun --> 函数名
	'''
	文档描述
	'''
    函数体
    return 值
"""

​ 1.1.1 三种定义方式

​ 定义函数不运行函数体代码, 但是会检查函数体语法

# 方式一: 无参函数 ---> 函数不需要接受值, 就可以完成所需功能
def func_1():
    print('122')
    
# 方式二: 有参函数 ---> 需要接受外部传值
def func_2(age):
    print(age)
    
# 方式三: 空函数: 函数体代码为pass ---> 构思代码使用
def func_3(age):
    pass

​ 1.1.2 三种调用方式

​ 通过函数名找到函数所在内存地址, 加()触发函数体代码执行

# 方式一: 语句形式, 只调用函数
func()

# 方式二: 表达式形式(赋值表达式, 数学表达式): 取函数的返回值
func()

# 方式三: 函数可以当成另一个函数的参数
func()

​ 1.1.3 三种返回值形式

​ return 后面的代码不执行, 并将return后的值当做运行结果返回

# 方式一: 返回None
func()

# 方式二: 返回一个值
func()

# 方式三: 返回多个值, 用 ',' 分割开, return一个元组
func()

2. 参数

位置参数必须放在放在关键字参数之前, 不能为同一个形参重复传值

2.1 形参: 在定义函数时定义的参数叫形式参数, 简称形参, 相当于变量名

2.2 实参: 在调用函数时, 传入函数的值称为实际参数, 简称实参, 相当于变量值

# 方式一: 
fun(1, 2)

# 方式二: 
a = 1
b = 2
func(a, b)

# 方式三: 
func(int('1'), 2)

2.3 位置参数

位置形参:

​ 函数定义时, 按从左到右的顺序依次定义的参数称之为位置参数

特点: 必须被传值, 不能多也不能少

位置实参:

​ 函数调用时, 按从左到右的顺序依次传入的值

特点: 按照顺序与形参一一对应

2.4 关键字参数

关键字实参:

​ 函数调用时, 按照key=value的形式传入值

特点: 可以完全不参照顺序给函数传值

2.5 默认形参

​ 在定义函数阶段, 就已经被赋值的形参, 称之为默认参数

特点: 在定义阶段就已经被赋值, 在调用阶段就可以不赋值

2.6 可变长参数

​ 指的是在函数调用时, 传入值的个数是不固定的 *args/**kwargs

​ *args: 用来接收溢出的位置实参 —> 元组形式接收

​ **kwargs: 用来接收溢出的关键字实参 —> 字典形式接收

​ **特点: **

================================================

(以下了解内容)

命名关键字参数:

​ 在定义函数是时, *后定义的参数称之为命名关键字参数

def func(x, y, *, a, b):
    print(x, y)
    print(a, b)

​ 特点: 命名关键字参数传参必须按照key=value的形式

================================================

3. 名称空间与作用域

名称空间加载顺序: 内置名称空间 > 全局名称空间 > 局部名称空间

名称空间销毁顺序: 局部名称空间 > 全局名称空间 > 内置名称空间

名字查找顺序: 当前所在位置向上一层一层查找

名称空间的嵌套关系是以定义阶段为准, 与调用位置无关(名称空间只有优先级之分, 本身无嵌套关系, 说嵌套是帮助理解)

LEGB: L: local E: enclosing G: global B: builtin

3.1 名称空间

​ 存放名字的地方, 是对栈区的划分

3.1.1 局部名称空间(局部范围)

​ 在调用函数时, 运行函数体代码时产生的名字

​ 存活周期:

3.1.2 全局名称空间(全局范围)

​ 运行顶级代码产生的名字

​ 存活周期: python文件执行产生, python文件运行完毕后销毁

3.1.3 内置名称空间(全局范围)

​ 存放python解释器内置的名字

​ 存活周期: python解释器启动产生, python解释器关闭销毁

3.2 作用域

​ 3.2.1 全局作用域(内置名称空间, 全局名称空间)

​ 特点: 全局存活, 全局有效, 被所有函数共享

​ 3.2.2 局部作用域(局部名称空间)

​ 特点: 临时存活, 局部有效, 函数内有效

3.3 global和nonlocal

​ global: 声明变量名是全局名, 不需要再造变量名

​ nonlocal: 修改函数外层函数包含的变量名对应的值

4. 函数嵌套

函数对象: 可以把函数当成变量用(可以赋值; 可以把函数当参数传给另一个函数; 可以当做另一个函数的返回值; 可以当做容器类型的一个元素)

4.1 函数嵌套调用

​ 在调用一个函数的过程中又调用其他函数

4.2 函数嵌套定义

​ 在函数内定义其他函数

4.3 闭包

​ 闭包函数 = 名称空间与作用域 + 函数嵌套 + 函数对象

​ 核心点: 名字的查找关系是以函数定义阶段为准的

​ ‘闭’函数指的是该函数的内嵌函数, ‘包’函数是指该函数包含对外层函数作用域名字的引用(不是对全局作用域)

# 定义闭包函数
def fun_1():
    x = 11
    def fun_2():
        print(x)
    return fun_2

5. 装饰器

​ 开放封闭原则: 对拓展功能是开放的, 对修改源代码是封闭的

​ 装饰器: 定义一个函数(类), 该函数用来装饰其他函数, 即为其他函数增加额外的功能

import time


def index_l(x, y):
    time.sleep(3)
    print(x, y)

    
def home(name):
    print(name)
    
    
def outter(func):
    def wrapper(*args, **kwargs):
        # 在不修改index_l源代码和调用方式的前提下增加函数运行时间的功能
        start_time = time.time()
        res = func(*args, **kwargs)
        stop_time = time.time()
        print(stop_time - start_time)
        return res
    return wrapper
    
    
index_l = outter(index_l)
home = outter(home)

index_l(1, '222')
home('12d')

语法糖:

import time


def timmer(func):
    def wrapper(*args, **kwargs):
        # 在不修改index_l源代码和调用方式的前提下增加函数运行时间的功能
        start_time = time.time()
        res = func(*args, **kwargs)
        stop_time = time.time()
        print(stop_time - start_time)
        return res
    return wrapper


@timmer
def index_l(x, y):
    time.sleep(3)
    print(x, y)
    
    
@timmer   
def home(name):
    print(name)
    
    
index_l(1, '222')
home()
# 无参装饰器模板
from functools import wraps
def outter(func):
    @wraps(func)  # 将原函数的属性赋值给wrapper函数
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    
    # 手动将原函数的属性赋值给wrapper函数
    # wrapper.__name__ = func.__name__
    # wrapper.__name__ = func.__doc__
    
    return wrapper


# 有参装饰器模板
def auth(x):
    def deco(func):
        def wrapper(*args, **kwargs):
            if x == 1:
                res = func(*args, **kwargs)
                return res
            else:
                print('被装饰函数不运行')
        return wrapper
    return deco

6. 迭代器与生成器

​ 迭代器: 指的是迭代取值的工具, 迭代是一个重复的过程, 每次重复都是基于上一次结果而继续的, 单纯的重复不是迭代(不依赖于索引取值)

​ 可迭代对象: 内置有.__ iter __ 方法的都是可迭代对象

l = [1, 2, 3, 4]

l_iterator = l.__iter__()
while True:
    try:
        print(l_iterator.__naex__())
    except StopIteration:
        break

​ 迭代器对象: 内置有.__ next __ 方法并且内置有.__ iter 方法的对象(. __ next ():得到下一个值, . __ iter (): 得到的是迭代器本身)

​ for 循环的工作原理:

 		1. 调用.__ __iter__ __()得到一个迭代器对象__
 		2. __迭代器对象.__ __next__ __()拿到一个返回值, 然后将该返回值返回赋值给变量名(i)
 		3. 循环步骤2, 直到抛出一个异常, for循环捕捉这个异常然后结束循环

迭代器优缺点:

​ 优点: 节省内存; 不受制于索引

​ 缺点: 只能取下一个值; 除非取完, 否则无法获取迭代器的长度(一次性)

生成器(自定义迭代器)

​ 在函数内一旦存在 yield 关键字, 调用函数时不会执行函数体代码, 会返回一个生成器对象, 生成器就是自定义迭代器

def func():
    # yield 可返回多个值
    print('1...')
    yield 1
    print('2...')
    yield 2
g = func()
print(g)
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
next(g)

生成器应用:

叠加多个装饰器:

# 加载顺序自下而上, 执行顺序自上而下
def outer_1(func_1):
    def wrapper_1(*args, **kwargs):
        print('outer_1.index_1 正在运行....')
        res_1 = func_1(*args, **kwargs)
        return res_1
    return wrapper_1


def outer_2(func_2):
    def wrapper_2(*args, **kwargs):
        print('outer_2.index_2 正在运行....')
        res_2 = func_2(*args, **kwargs)
        return res_2
    return wrapper_2


def deco_1(num):
    def outer_3(func_3):
        def wrapper_3(*args, **kwargs):
            print('deco_1.outer_3.index_3 正在运行....', num)
            res_3 = func_3(*args, **kwargs)
            return res_3
        return wrapper_3
    return outer_3


@outer_1
@outer_2
@deco_1(333)
def index_demo(x, y):
    print(x, y)
    return x, y


print(index_demo(1, 4))

yield的表达式形式

def func_1(num):
    print(num, '是传入的参数.....', sep='')
    while True:
        x = yield 'yield 的返回值'
        print(x, '是yield接收到的值......', sep='')


g = func_1(222)
print(g.send(None))  # 等同于 next(g)
print(g.send('111'))

三元表达式

三元: 条件 条件成立 条件不成立

x = 3
y = 2
res = x if x > y else y
print(res)

列表生成式

l = [1, 2, 3, 4, 5]
new_l = [num for num in l]
new_l = [num for num in l if num > 2]

其他生成式

# 字典生成式
items = [('name', 'xxx'), ('age', 18), ('gender', 'male')]
res = {k: v for k, v in items if k != 'gender'}
print(res)

# 集合生成式
items = [('name', 'xxx'), ('age', 18), ('gender', 'male')]
res = {k for k, v in items if k != 'gender'}
print(res)

# 生成器表达式
g = (i for i in range(10) if i > 3)
print(next(g))



# 统计文件字符个数
with open('name_file.txt', mode='r', encoding='utf-8') as f:
    # # 方法一
    # res = 0
    # for line in f:
    #     res += len(line)
    # print(res)

    # # 方法二
    # res = sum([len(line) for line in f])
    # print(res)

    # 方法三: 效率最高
    res = sum(len(line) for line in f)  # sum(len(line) for line in f) 等同于 sum((len(line) for line in f))
    print(res)

7. 递归

递归的本质是循环

# 直接调用函数本身
def func_1():
    print('这是一个递归函数, 调用本身')
    func_1()
   

# 间接调用函数
def func_1():
    print('func_1 调用了 func_2')
    func_2()
   

def func_2():
    print('func_2 调用了 func_1')
    func_1()

递归的两个阶段

​ 回溯: 一层一层调用

​ 递推: 满足某种结束条件, 结束调用, 然后一层一层返回

8. 函数类型提示功能

python语言是解释型, 强类型, 动态型的语言

# : 后面添加提示信息
def func(name: str, age: int, hobbies: tuple)->int:  # -> 后面是返回值的类型
    print(name, age, hobbies)
    return 2333333

# 添加默认值
def func(name: str='xx', age: int=18, hobbies: tuple=('111', '222'))->int:  # -> 后面是返回值的类型
    print(name, age, hobbies)
    return 2333333

# 查看函数提示信息
print(func.__annotations__)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值