Python 函数参数详解

  Python函数定义时参数灵活,使用不同参数的组合不仅可以简化调用者的代码,还可以处理复杂的参数。函数的参数除了有必选参数外,还可以使用默认参数,可变参数,关键字参数和命名关键字参数。

位置参数

定义一个计算x^2 的函数,以及一个计算x^n的函数

def calc1(x):
    return x * x

def calc2(x, n):
    s = 1
    for i in range(n):
        s *= x
    return s

对于这两个函数,其参数都是位置参数,同时也是必选参数,调用函数时实参需和形参一一对应,当参数不对应时会引起错误,例如:

>>>calc2(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: calc2() takes exactly 2 arguments (1 given)

>>>calc2(2, 2, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: calc2() takes exactly 2 arguments (3 given)

默认参数

对于函数calc2,如若函数调用过程中,计算x^2使用的较多,每次调用都要通过calc2(x, 2)来调用,这样就略显繁琐,此时可以通过默认参数来简化函数的调用,改写函数为:

def calc3(x, n = 2):
    s = 1
    for i in range(n):
        s *= x
    return s

这样,我们在调用calc3(2)时,就相当于调用calc3(2, 2),而对于其他次方仍需明确指出n。默认参数在使用中应当的注意:位置(必选)参数在前,默认参数在后。

当有多个默认参数时,既可以按顺序提供默认参数,也可以不按顺序提供默认参数。

def saveInfo(name, gender, age = 23, city = 'HangZhou'):
    print(name, gender, age, city)

saveInfo('Alen', 'M', city='Beijing')

定义默认参数时需要特别注意的一点:默认参数必须指向不变对象!
看如下例子:

def addEnd(L=[]):
    L.append('END')
    return L

>>>addEnd()
['END']
>>>addEnd()
['END', 'END']
>>>addEnd()
['END', 'END', 'END']

出现这样的结果是因为:默认参数L仅仅代表[]的一个引用,函数定义时[]就已确定,每次调用addEnd时,使用的都是函数定义时的[],通过print(id(L))可以看出,每次调用该函数时使用的是同一内存地址的[]。

def addEnd(L=[]):
    L.append('END')
    print(id(L))
    return L

addEnd()
#4518465224
#['END']
addEnd()
#4518465224
#['END', 'END']

为了避免这个问题,可以通过下面的方式,每次调用函数时,都会新建一个[]:

def addEnd(L=None):
    L = [] if L == None else L
    L.append('END')
    print(id(L))
    return L

addEnd()
#4518687688
#['END']
addEnd()
#4518688328
#['END']

可变参数

可变参数即传入的参数个数是可变的,可以是0个,1个,或多个 先定义一下函数,给定一组数字a,b,c...,计算这组数字的平方和a^2 + b^2 + c^2 + ...

def calc(numbers):
    s = 0
    for num in numbers:
        s = s + num * num
    return s

该函数在调用时,需先组装一个list或tuple

>>>calc([1, 2, 3])
14
>>>calc([1, 2, 3])
30

如果利用可变参数,函数的调用可以简化

def calc(*numbers):
    s = 0
    for num in numbers:
        s = s + num * num
    return s

calc()
# 0
calc(1, 2, 3)     
# 14
calc(1, 2, 3, 4)
# 30

可变参数与list或tuple参数相比,仅仅在参数前面加了个号,*的作用是将传入的参数组装成一个tuple*
,如果已经有一个list或tuple,要调用可变参数怎么办呢?

>>>nums = [1, 2, 3]
>>>calc(nums[0], nums[1], nums[2])
14

这种写法就过于繁琐,针对这种情况,python允许在list或tuple前加一个*号,将list或tuple的元素变成可变参数传入

>>>nums = [1, 2, 3]
>>>calc(*nums)
14

关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
定义一个用户注册的函数

def user(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

user('Bob', 23)          
# ('name:', 'Bob', 'age:', 23, 'other:', {})
user('Alen', 20, gender='M', job='Engineer') 
# ('name:', 'Alen', 'age:', 20, 'other:', {'gender': 'M', 'job': 'Engineer'})

函数user除了接收必选参数name,age外还接收关键字参数kw,调用该函数时,可以只传入必选参数,也可以传入任意个数的关键字参数,**的作用是将含参数名的参数,组装成一个dict传入kw。关键字参数可以扩展函数的功能,调用者如果提供更多的信息,我们仍可以接收到。例如当用户注册时,姓名和年龄时必填项,其他是可选项,就可以通过关键字参数来实现。
和可变参数类似,当有现成dict时,可通过以下方式简化调用:

>>>extra = {'city': 'Beijing', 'job': 'Engineer'}
user('Bob', 23, **extra)
name: Bob age: 23 other: {'city': 'Beijing', 'job': 'Engineer'}

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict。注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数,如果要限制关键字参数的名字,就可以用命名关键字参数。命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数,例如,只接收city和job作为关键字参数:

def user(name, age, *, city, job):
    print('name:', name, 'age:', age, 'city:', city, 'job:', job)

user('Alen', 20, city='Beijing', job='Engineer') 
# name: Alen age: 20 city: Beijing job: Engineer

不同于位置参数,命名关键字参数必须传入参数名。如果没有传入参数名,调用将报错:

>>>user('Alen', 20, 'Beijing', 'Engineer')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: user() takes 2 positional arguments but 4 were given

若函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def user(name, age, *args, city, job):
    print(name, age, args, city, job)

命名关键字参数可以有缺省值,从而简化调用:

def user(name, age, *, city='Beijing', job):
    print(name, age, city, job)

user('Bob', 22, job='Engineer')
# Bob 22 Beijing Engineer

参数组合

定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是应注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
定义一个函数,包含上述参数:

def user(name, age = 20, *args, city = 'Beijing', job, **kw):
    print(name, age, args, city, job, kw)

user('Bob', 20, 120, job = 'Engineer', gender = 'M')
# Bob 20 (120,) Beijing Engineer {'gender': 'M'}

对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。

>>>args = ('Bob', 20, 120)
>>>kw = {'job':'Engineer', 'gender':'M'}
>>>user(*args, **kw)
Bob 20 (120,) Beijing Engineer {'gender': 'M'}

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

推荐阅读更多精彩内容

  • 第5章 函数和函数式编程 5.1 引言函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数...
    VIVAFT阅读 898评论 0 5
  • 1.函数参数 1.1 位置参数 我们先写一个计算x2的函数: 对于power(x)函数,参数x就是一个位置参数。当...
    时间之友阅读 355评论 0 2
  • 一、位置参数 例如我们写一个计算x²的函数: 对于power(x)函数,参数x就是一个位置参数。当我们调用powe...
    劉光軍_MVP阅读 240评论 0 1
  • Python 是一种相当高级的语言,通过 Python 解释器把符合语法的程序代码转换成 CPU 能够执行的机器码...
    Python程序媛阅读 1,865评论 0 3
  • [玫瑰][玫瑰][玫瑰][强][强][强] 比尔盖茨说:“赚不到钱,并不是没钱可赚,而是你不在赚钱的圈子内。 马云...
    励志女神糖糖阅读 138评论 0 0