Python3 函数的更高级的话题(一)

本次我要给大家分享一些更加高级和不常见的函数定义与使用模式。

涉及到的内容包括默认参数、任意数量参数、强制关键字 参数、注解和闭包等。

* 表达式

我们知道在定义函数的时候,用 * 表达式来收集所有未指明的位置参数。

def avg(first, *rest):
    """求平均值"""
    return (first + sum(rest)) / (1 + len(rest))
    
# 简单使用
avg(1, 2)  # 1.5 
avg(1, 2, 3, 4)  # 2.5

当然在调用函数的时候,也可以使用 * 表达式来把一个序列类型数据中的元素一一解开。

def show_args(*args):
    print(args)

show_args(['a','b'])  # (['a', 'b'],)
show_args(*['a','b'])  # ('a', 'b')

print() 函数的另外一种用法

print(['a','b'], sep='\n') 
# ['a', 'b']

print(*['a','b'], sep='\n')
# a
# b

print(*'ab', sep='\n')
# a
# b

其实 print() 函数的原型是这样定义的

def print(self, *args, sep=' ', end='\n', file=None):
    pass

print() 函数中的 sep 关键字参数定义的是当打印多个参数时,它们中间的分隔符是什么

** 表达式

def foo(**kwargs):
    print(kwargs)  # 是一个字典

一个 * 参数只能出现在函数定义中最后一个位置参数的后面,而 ** 参数只能出现在最后一个参数都位置。
有一点要注意的是,在 * 参数后面其实还可以定义其他参数。下面就会用到。

在函数中实现强制关键字参数

有的时候你希望在调用函数的时候,必须用关键字参数,因为这样更易懂。
可以将要限定的强制关键字参数放到某个 *参数 或者单个 * 后面就能达到这种效果。
像下面这样。

def query_keyword(max_file, *, servers):
    pass

query_keyword(65535, servers=False)  # ok
query_keyword(65535)  # TypeError

使用函数注解

函数注解是为了让看这个函数源码的人更能清楚参数的类型和用法

 def add(x:int, y:int) -> int: 
     return x + y

python 解释器不会对这些注解添加任何的语义。它们不会被类型检查,运行时跟 没有加注解之前的效果也没有任何差距。

这些注解存储在函数的 __annotations__ 属性中。
print(add.__annotations__)

感受 return 的强大

def foo():
    return '千锋', 8, 1000000

name, *nums = foo()

print(name)  # 千锋
print(nums)  # [8, 1000]

其实在函数返回之前,先创建了一个元组,之后的赋值就是我们之前讲的元组解包

在定义函数的默认参数时,不要用可变类型的数据

假如你的确需要一个默认参数是一个可边类型的数据(比如列表)
可以把默认参数的值先定义为 None

def foo(a, b=None): 
    if b is None:
        b = []

验证同一性

假如你想在一个函数中判断使用者有没有给一个参数传参,你可能想到这样:

def spam(a, b=None)
    if not b:  # 判断是否是 False
        print("用户没有传递变量")

这样显然会有问题的,因为对于 python 来说, 长度为 0 的字符串 ''、列表 []、元组 ()、字典 {} 都会认为是 False, 并且数字 0 和 布尔值的 False 都认为是假的。
也就是说用户传入这些参数是属于合法的参数。

解决办法:

_no_value = object()
def spam(a, b=_no_value): 
    if b is _no_value:
        print("用户没有传递变量")

_no_valueobject() 的是个实例, 这样可以判断变量 b 的值和 _no_value 的值是否是同一个对象来判断用户是否传入了值。

匿名函数

在匿名函数中使用了一个变量的值,这会是很有意思的一件事。

li = [lambda n=30: n for n in range(10)]

现在你回答下面几个问题

  1. li[0] 是什么类型的对象?

li 是一个列表,其中的元素都是匿名函数

  1. li[0]()li[1]() 分别都是什么值?

其实 li[0]()li[1]() 的值都是 9

lambda 表达式中的 n 是一个自由变量,是在运行时给其绑定值,而不是在定义时就给其绑定值,这跟函数的默认值参数定义是不同的。
因此,在调用这个 lambda 表达式的时候,n 的值是执行时的值。
还有要考虑到, 在 Python 中只有在函数中定义的变量才是局部变量,其他都是全局的变量。 for 循环到最后 n 的值被绑定为 9, 所以 li 所用函数中的 n 的值在运行时都是 9

现在对 lambda 函数稍作修改就会有不一样的效果

funcs = [lambda n=n: n for n in range(10)]
funcs[0]()  # 0
funcs[1]()  # 1

等号左边的 n 是函数的形参,右边是函数的实参,实参也就是迭代的变量的值。
这里利用默认参数,就可以在定义函数时,把值绑定给变量。

未完, 待续...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容