Python 函数之一(定义及参数)

一、函数

1.1 数学定义
  • y=f(x)yx 的函数,x 是自变量,y=f(x0, x1, ..., xn)
1.2 Python 函数
  • 有若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元
  • 完成一定的功能
1.3 函数的作用
  • 结构化编程对代码的最基本的封装,一般按照功能组织一段代码
  • 封装的目的为了复用,较少冗余代码
  • 代码更加简洁美观、可读易懂
1.4 函数的分类
  • 内建函数,如 max()reversed()
  • 库函数,如 math.ceil()
  • 自定义函数,使用 def 关键字定义

二、函数定义

def 函数名(参数列表):
    函数体 (代码块)
    [return 返回值]
  • 函数名就是标识符,命名要求一样
  • 语句块必须缩进,约定 4 个空格
  • Python 的函数若没有 return 语句,会隐式返回一个 None
  • 定义中的参数列表称为 形式参数,只是一种符号表达(标识符),简称 形参

三、函数调用

  • 函数定义,只是声明了一个函数,它不能被执行,需要调用执行
  • 调用的方式,就是 函数名后加上小括号,有必要在括号内填写上参数
  • 调用时写的参数是 实际参数,是实实在在传入的值,简称 实参
def add(x, y):   # 定义函数
    result = x + y   # 函数体
    return result   # 返回值

out = add(4, 5)   # 调用函数,可能有返回值,使用变量接收这个返回值
print(out)   # print 函数加上小括号也是调用
  • 上面代码解释
    • 定义一个函数 add,及函数名是 add,接受 2 个参数
    • 该函数计算的结果,通过返回值返回,需要 return 语句
    • 调用时,通过函数名 add 后加 2 个参数,返回值可使用变量接收
    • 函数名也是标识符,返回值也是值
    • 定义需要在调用前,也就是说调用时,已经被定义过了,否则抛 NameError 异常
    • 函数是 可调用对象callable()

四、函数参数

函数在定义时要约定好形式参数,调用时也提供足够的实际参数,一般来说,形参和实参个数要一致(可变参数除外)

4.1 位置传参
  • 定义时 def func(x, y, z),调用使用 func(1, 3, 5),按照参数定义顺序传入实参
4.2 关键字传参
  • 定义时 def func(x, y, z),调用使用 func(x=1, y=3, z=5),使用形参的名字来传入实参的方式,若使用了形参名字,那么传参顺序就可和定义顺序不同

  • 要求位置参数必须在关键字参数之前 传入,位置参数是按位置对应的

def func(x, y, z):
    pass

func(z = None, y = 10, x = [1])
func((1,), z =  6, y = 4.1)
func(y = 5, z = 6, 2)   # 错误传参
4.3 参数缺省值

缺省值也称为默认值,可在函数定义时,为形参增加一个缺省值

  • 参数的默认值可在未传入足够的实参的时候,对没有给定的参数赋值为默认值
  • 参数非常多的时候,并不需要每户每次都输入所有的参数,简化函数调用
def add(x = 4, y = 5):
    return x + y

测试调用 add()、add(x = 5)、add(y = 7)、add(6, 10)、add(6, y = 7)、add(x = 5, y = 6)、add(y = 5, x = 7)

add(x = 7, 8)、add(y = 8, 4)、add(11, x=20)

能否这样定义 def add(x, y = 5) 或 def add(x = 4, y)
# 定义一个函数 login,参数名称为 host、port、username、password
def login(host='127.0.0.1', port='8080', username='rookie', password='rookie'):
    print('{}:{}@{}/{}'.format(host, port, username, password_+))

login()
login('127.0.0.1', 80, 'tom', 'tom')
login('127.0.0.1', username='jerry')
login('localhost', port=80, password='com')
login(port=80, password='http', host='www')
4.4 可变参数

需求:写一个函数,可对多个数累加求和

def sum(iterable):
    sum = 0
    for x in iterable:
        sum += x
    return sum

print(sum([1, 3, 5]))
print(sum(range(4)))

上例,传入可迭代对象,并累加每一个元素
也可使用可变参数完成上面的函数

def sum(*nums):
    sum = 0
    for x in nums:
        sum += x
    return sum

print(sum([1, 3, 5]))
print(sum(1, 2, 3))
  • 可变位置参数

  • 在形参前使用 * 表示该形参数可变位置参数,可接收多个实参

  • 它将收集来的实参组织到一个 tuple

  • 可变关键字参数

    • 在形参前使用 ** 表示该形参是可变关键字参数,可接收多个关键字参数
    • 它将收集来的实参的名称和值,组织到一个 dict
def showconfig(**kwargs):
    for k,v in kwargs.items():
        print('{}={}'.format(k,v),end=', ')

showconfig(host='127.0.0.1', port=8080, username='rookie', password='rookie')

混合使用

def showconfig(username, password, **kwargs)
def showconfig(username, *args, **kwargs)
def showconfig(username, password, **kwargs, *args)
  • 总结

    • 有可变位置参数和可变关键字参数
    • 可变位置参数在形参前使用一个星号 *
    • 可变关键字参数在形参前使用两个星号 **
    • 可变位置参数和可变关键字参数都可收集若干实参,可变位置参数收集形成一个 tuple,可变关键字参数收集形成一个 dict
    • 混合使用参数的时候,普通参数需要放到参数列表前面,可变参数要放到参数列表的后面,可变位置参数需要在可变关键字参数之前
  • 使用举例

def fn(x, y, *args, **kwargs):
    print(x, y, args, kwargs, seq='\n', end='\n\n')

fn(3, 5, 7, 9, 10, a=1, b='abc')
fn(3, 5)
fn(3, 5, 7)
fn(3, 5, a=1, b='abc')
fn(x=3, y=8, 7, 9, a=1, b='abc')
fn(7, 9, y=5, x=3, a=1, b='abc')

fn(x=3, y=8, 7, 9, a=1, b='abc'),错在位置传参必须在关键字传参之前
fn(7, 9, y=5, x=3, a=1, b='abc'),错在 79 已经按照位置传参给 xy,后面 x=3, y=5 传参重复

4.5 keyword=only 参数

先看一段代码

def fn(*args, x, y, **kwargs):
    print(x, y, args, kwargs, seq='\n', end='\n\n')

fn(3, 5)
fn(3, 5, 7)
fn(3, 5, a=1, b='abc')
fn(3, 5, y=6, x=7, a=1, b='abc')

在 Python3 之后,新增了 keyword-only 参数
keyword-only 参数:在形参定义时,在一个 * 之后,或一个可变位置参数之后,出现的普通参数,就已经不是普通的参数了,被称为 keyword-only 参数

def fn(*args, x):
    print(x, args, seq='\n', end='\n\n')

fn(3, 5)
fn(3, 5, 7)
fn(3, 5, x=7)

keyword-only 参数,言下之意就是这个参数必须采用关键字传参
可任务,上例中,args 可变位置参数已经截获了所有位置参数,其后的变量 x 不可能通过位置传参传入了

def fn(**kwargs, x):
    print(x, kwargs, seq='\n', end='\n\n')

上例中的定义方式,不可行,语法错误
可认为,kwargs 会截获所有关键字传参,就算写了 x=5x 也没有机会得到这个值,所以这种语法不存在

keyword-only 参数另一种形式
* 后所有的普通参数都成了 keyword-only 参数

def fn(*, x, y):
    print(x, y)

fn(x=6, y=7)
fn(y=8, x=9)
4.6 参数的混合使用
# 可变位置参数、keyword-only 参数、缺省值
def fn(*args, x=5):
    print(x)
    print(args)

fn()   # 等价于 fn(x=5)
fn(5)
fn(x=6)
fn(1, 2, 3, x=10)
# 普通参数、可变位置参数、keyword-only 参数、缺省值
def fn(y, *args, x=5):
    print('x={}, y={}'.format(x, y))
    print(args)

fn()   #
fn(5)
fn(5, 6)
fn(x=6)   #
fn(1, 2, 3, x=10)
fn(y=17, 2, 3, x=10)   #
fn(1, 2, y=3, x=10)   #
# 普通参数、缺省值、可变关键字参数
def fn(x=5, **kwargs):
    print('x={}'.format(x))
    print(kwargs)

fn()
fn(5)
fn(x=6)
fn(y=3, x=10)
fn(3, y=10)
fn(y=3, z=20)
4.7 参数规则

参数列表参数一般顺序是:普通参数、缺省值参数、可变位置参数、keyword-only 参数(可带缺省值)、可变关键字参数

  • 注意:
    • 代码应该易读易懂,而不是为难别人
    • 请按照书写习惯定义函数参数
def fn(x, y, z=3, *args, m=4, n, **kwargs):
    print(x, y, z, m, n)
    print(args)
    print(kwargs)

def connect(host='localhost', port='3306', user='admin', password='admin', **kwargs):
    print(host, port)
    print(user, password)
    print(kwargs)
connect(db='cmdb')
connect(host='192.168.1.123', db='cmdb')
connect(host='192.168.1.123', db='cmdb', password='mysql')
  • 定义最常用参数为普通参数,可不提供缺省值,必须由用户提供,注意这些参数的顺序,最常用的先定义
  • 将必须使用名称的才能使用的参数,定义为 keyword-only 参数,要求必须使用关键字传参
  • 若函数有很多参数,无法逐一定义,可使用可变参数,若需要知道这些参数的意义,则使用可变关键字参数收集

五、参数解构

def add(x, y):
    print(x, y)
    return x + y

add(4, 5)
add((4, 5))
t = 4, 5
add(t[0] + t[1])
add(*t)
add(*(4, 5))
add(*[4, 5])
add(*{4, 5})
add(*range(4, 6))

add(*{'a':10, 'b':11})
add(**{'a':10, 'b':11})   #
add(**{'x':100, 'y':110})

参数解构

  • 在给函数提供实参的时候,可在可迭代对象前使用 *** 来进行结构的解构,提取出其中所有元素作为函数的实参
  • 使用 * 解构成位置传参
  • 使用 ** 解构成关键字传参
  • 提取出来的元素数目要和参数的要求匹配
def add(*iterable):
    result = 0
    for x in iterable:
        result += x
    return

add(1, 2, 3)
add(*[1, 3, 4])
add(*range(5))

六、练习

6.1 编写一个函数,能够接受至少 2 个参数,返回最小值和最大值
def getvalues(min, max, *iterable):
    for x in iterable:
        if min > x:
            min = x
        if max < x:
            max = x
    return min, max

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

推荐阅读更多精彩内容