Python学习 之 函数


函数入门

语法和参数顺序

"""
	语法:
		关键字 函数名(参数列表):
			函数体
	
	参数顺序:
		位置参数: a, b, c
		未知数量位置参数, *args, 接收进函数内的类型为 tuple
		关键字参数: key=None
		未知关键字参数, **kwargs, 接收进函数内的类型为 dict

"""

# 顺序: 位置参数 -> *args -> 关键字参数 -> **kwargs
def func(a, *args, b=None, **kwargs):
    print(a, args, b, kwargs)


func(1,2,3,b=10,sex="女",tips="提示")       # 1 (2, 3) 10 {'sex': '女', 'tips': '提示'}

    # 特殊用法: 传参时使用 * 或 **, 将元组或字典打散, 再传参
    x = (2,3)
    y = {"sex":"女","tips":"提示"}
    d(1,*x,b=10,**y)                        # 1 (2, 3) 10 {'sex': '女', 'tips': '提示'}


特殊用法 - 打散传参

""" 可以使用 * 打散 list 和 tuple, 用 ** 打散 dict 进行传参 """

def a(*args, **kwargs):
    print(args, kwargs)

t = (1, 2, 3)
d = {"a": 1, "b": 2}

a(t, d)    # ((1, 2, 3), {'a': 1, 'b': 2}) {}, 并未将 dict 中的键值对作为关键字参数传入
a(*t, **d) # (1, 2, 3) {'a': 1, 'b': 2}


概念

命名空间

  • 作用: 存放变量与值的内存地址的对应关系
  • 命名空间
    • 全局命名空间
    • 临时命名空间(局部命名空间), 当函数执行完毕时, 临时命名空间消失
    • 内置命名空间
  • 作用域
    • 全局作用域: 全局命名空间 内置命名空间
    • 局部作用域: 局部命名空间
  • 取值顺序
    • 局部命名空间(函数执行时) --> 全局命名空间 --> 内置命名空间
  • 加载顺序
    • 与取值相反

方法: globals() 和 locals()

""" 
	局部命名空间, 打印该局部空间的所有变量
	全局命名空间, 无论放在哪里, 只打印全局的, 不打印局部的
	
"""
def x():
    i = 20	
    print(locals())
    # 结果: {'i': 20}

    print(globals())
    # 结果: {'__name__': '__main__', '__doc__': None, '__package__': None, ...}

if __name__ == "__main__":
    x()


关键字: global 和 nonlocal

# 全局变量
a = 10
b = 20

def x():
	# global 关键字声明函数 x 内部使用全局变量 a
    global a
    a = 100 # 修改了全局变量

	# 定义一个局部变量 b, 这个和全局变量不冲突, 当函数执行完成后会销毁
    b = 200

    def y():
    	# nonlocal 关键字声明函数 y 内部使用局部变量 b
        nonlocal b
        b = 2000 # 修改了局部变量

    # 调用内部的方法
    y()
    # 将 a, b 返回, 验证结果
    return a, b

if __name__ == "__main__":
    print(x()) #(100, 2000)


高级用法

闭包和验证闭包

"""
	内层函数对外层函数的非全局变量进行引用, 就是闭包
    可以使用 __closeure__ 进行判断, 如果是, 则返回一个内存地址, 如果不是, 则返回为空

"""

def func_outside():
    # 这个是外层函数的非全局变量
    x = 10 

    # 这个就是内层函数
    def func_inside():
        # 这里对外层变量 x 进行引用, 不需要做任何操作
        nonlocal x 
    
    # 执行内层函数
    b()

    # 通过__closure__方法判断
    print(b.__closure__)

if __name__ == "__main__":
    a() # 结果是一个内存地址, 所以它是闭包
    

lambda 表达式(匿名函数)

"""
	用于定义简单的函数逻辑
	多配合其他函数使用
	
	lambda 函数的语法示例:
    lambda i: i * 2
    lambda i: True if i % 2 == 0 else False
		
"""

# 定义 lambda 表达式
r = lambda x: x*2
# 执行函数, 正常传参
r(2)

# 配合其他函数使用, https://blog.csdn.net/yang_kaiyue/article/details/80068208 也有示例
r = filter(lambda x: False if x % 2 == 0 else True)
print(list(r))


递归函数

定义

  • 递归调用, 在调用一个函数的过程中, 直接或间接的调用函数本身, 称之为递归调用
  • 递归的必备两个阶段: 1. 递推 2. 回溯
  • python 中没有尾递归优化, 又占资源, 所以 python 的递归效率低
  • 递归需要有明确的结束

示例

"""
    常用于反推和递推的模型
	    反推: 已知最后一个的信息, 反推第一个的信息
	    递推: 从第一个一直向后, 直到满足条件
	    内部一定有一个 if 判断, 用于结束递归

"""

# 1. 第一个人比第二个人大 2 岁, 第二个人比第三个人大 2 岁, 第三个人 18 岁, 问第一个人多大

# 参数理解为总数(递归深度)
def funcA(n):
    # n 为 1 时, 拿到最后一个的确切信息, 并返回
    if n == 1:
        return 18
    # 需要回溯(根据下层数据计算上层数据), 需要 return
    # 调用本身, 深度-1,并且处理不同深度的数据差异
    else:
        return funcA(n-1)+2

print(funcA(3))

# 2. 依次打印所有元素

l = [1, [2, [3, [4, [5, [6, 7]]]]]]

def funcB(l):
    for i in l:
        if type(i) == list:
            funcB(i)
        else:
            print(i)

funcB(l)


高级应用

三级菜单
"""
    省/市 -> 区 -> 地名 -> 公司名
    
"""

menu = {
    '北京': {
        '海淀': {
            '五道口': ['soho', '网易', 'google'],
        },
        '朝阳': {
	        '国贸': [],
        },
        '东城': {},
    },
    '山东': {},
}


def choose_menu(d):
    # 判断是否在无法展开的子菜单(因为只有最末端为 list 类型)
    if type(d) == list:
        print("查询结果为 %s" % str(list(d)))
    else:
        # 展示菜单
        for i in d:
            print(i, end=" ")

        # 拿到查询选项
        k = input("input: ")

        # 判断如果选项在菜单中, 且菜单内容不为空
        if k in d and len(d[k]) != 0:
            choose_menu(d[k])
        else:
            print("查询结果为空")


choose_menu(menu)


二分查找算法
def find_num(l, num, start=0, end=None):
    # 因为是有序算法, 先确定边界
    if num < l[0] or num > l[-1]:
        return "超出有序数列范围"
    
    # 如果未传start和end参数, 则设置为整个列表
    if not end:
        end = len(l)

	# 如果索引是相邻的且起始位置不为0, 那么可以判定这个数字不在数列中
    if end-start == 1 and start != 0 :
        return "找不到这个数字"

    # 计算中间值
    mid = (start+end)//2
    
    if num == l[mid]:
        return mid
    elif num > l[mid]:
         return find_num(l,num,mid,end)
    elif num < l[mid]:
        return find_num(l,num,start,mid)

l = [10,20]

# 找 10 在列表l中的索引
print(find_num(l,10))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值