Python函数

函数主要有定义和调用两个阶段,在定义阶段,解释器只检查语法,不会执行代码,解释器默帮我们定义了一些内置函数,如常用的print(),len()等。
定义一个函数:

def print_s():
    print('*'*15)
    print('hello'.center(15,'*'))
    print('*'*15)
print_s()

函数一般的定义方式:

def  function_name(arg1,arg2,arg3):
    # 注释
    函数体
    return 返回值

函数名一般是动词,定义的三种方式:

  • 无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印。
  • 有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大最小值。
  • 空函数:设计代码结构

return
return: 函数内部可以有多个return,但只能执行一次,函数就结束调用,并且会把return后的值作为函数执行的结果返回。

  • return 的返回值没有类型限制
  • 如果函数中没有return,则返回None,等同于return None. 如果只是执行一系列的操作,不需要结果则无需返回值。
  • return 一个值: 返回该值
  • return val1,val2,val3 :返回(val1,val2,val3)

函数调用的三种形式

1.语句形式,语句直接调用:

foo()

2.表达式形式,直接带入进行运算:

3*len('python')

3.函数中,使用另一个函数(返回值)作为参数:

max(max(1,2),3)

函数的参数

函数的参数分为形参和实参两种:

  • 实参:在调用函数时,括号内的参数称为实参,实参就是变量值
  • 形参: 在调用阶段变量值才会绑定形参(变量名),调用结束后,接触绑定。

参数的分类:

  • 位置参数: 按照从左到右的顺序依次定义的参数
    • 位置形参: 必须被传值,并且要不多不少
    • 位置实参: 与形参按照位置一一对应
    • 关键字实参: 指的是按照name=value的形式,给指定的参数赋值,并不一定需要按位置顺序赋值。

提示:
* 位置实参必须在关键字实参的前面
* 一定不要对同一个形参传多次值

默认参数

默认参数一般是形参,在定义阶段就已经为形参传值,在赋值的时候可以使用默认值,也可以单独赋值。

def newuser(name,age,sex='male'):
    print(name,age,sex)

newuser('tt',18)
newuser('yy',22,'female')

提示:
* 默认参数必须放在位置参数之后
* 默认参数值在定义阶段赋值一次,而且仅一次。
* 默认参数的值应该定义成不可变类型。

可变长参数

可变长参数指的是多个实参的个数可以任意变化,实参分为位置实参和关键字实参两种:

  • 按照位置定义的实参溢出的情况使用:*
def foo(x,y,*args):
    print(x)
    print(y)
    print(args)
foo(1,2,3,4,5)

输出的内容为变量值和元组。

  • 按照关键字定义的实参溢出的情况:**
def foo(x,y,**kwargs):
    print(x)
    print(y)
    print(kwargs)
foo(x=1,y=2,a=3,b=4,c=5)

输出的内容为变量值和列表。
在有些场景下,为了后期代码的维护和扩展,会使用一个中间函数(wrapper())对函数参数进行传递,可以接受任意长度,任意形式的参数,而不改变原本的参数顺序和属性:

def foo(name,age,sex='male'):
    print(name)
    print(age)
    print(sex)
def wrapper(*args,**kwargs):
    print(args)
    print(kwargs)
    foo(*args,**kwargs)

提示:关键字实参一定要在位置实参的后面

命名关键字参数

*后面定义的 形参称为命名关键字参数
,必须是以关键字实参的形式传值。

def foo(name,age,*,sex):  # * 后面的sex为命名关键字参数,对其传值需要指明关键字,否则会报错。
    print(name)
    print(age)
    print(sex)
foo('andy',22,sex='male')    # sex必须以关键字形式传值
参数的使用顺序

如果将多个参数放在一个函数中,那么他们必须遵循以下顺序规则:

  1. 位置形参 name
  2. 默认参数 age=22
  3. 可变长参数 *args
  4. 命名关键字参数(一般在*后) sex=male
  5. 多值关键字参数 **kwargs

函数对象

函数的定义类似与变量的定义,可以当作对象来赋值:

def foo():
    print('from foo')
f=foo     # 函数本身被当作对象赋值
f()         # 执行 f()

可以当作函数的参数传入:

def foo():
    print('from foo')
def wrapper(func):
    print(func)
wrapper(foo)

可以当作函数的返回:

def foo():
    pass
def wrapper(func):
    return func
res=wrapper(foo)
print(res)

可以当作容器类型的元素:

def foo():
    pass
cmd_dic={'func':foo}
print(cmd_dic)
cmd_dic['func']()

函数嵌套

在调用一个函数的过程中调用另一个函数:

def foo1():
    print('from foo1')
def foo():
    print('from foo')
    foo1()
foo()

函数的嵌套可以使代码简洁,逻辑更加清晰。在函数内部定义的定义的变量和函数只能在函数的内部访问。

名称空间

名称空间是存放名字和变量值绑定关系的区域。
分为内置名称空间,全局名称空间,局部名称空间。内置名称空间:在python 解释器启动时产生,存放一些python内置的名字。
全局名称空间: 在执行文件时产生,存放文件级别定义的名字,非内置和非函数中定义的为全局名称。
局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数局部名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效。
时那个名称空间的加载顺序:
内置名称空间 > 全局名称空间 > 局部名称空间
名称空间的查找顺序:
在局部定义: 局部 > 全局 > 内置
在全局定义: 全局 > 内置

在执行的当前位置作为起始,一层一层往上找。

作用域
分为全局作用域和局部作用域。
全局作用域:全局存活,全局有效
局部作用域:临时存活,只在局部有效。
全局的局部其实也是全局本身。

对全局的不可变类型如果在函数内部要进行修改,需要添加global。
对全局的可变类型进行修改在函数内部直接修改即可

x=1
def f():
    global x    # 全局的不可变类型需要添加global
    x=2
l=[1,2,3]
def f():
    l.append(4)

对于多层函数中定义的变量,如果要修改上层变量,可以使用nonlocal的关键字

def f1():
    x=1
    def f2():
        x=2
        def f3()
            nonlocal x   # 此时修改的是f2中的值
            x=3
        f3()
    f2()
f1()

作用域关系,在函数定义时就已经固定,与调用位置无关。

x=1
def f1():
    def f2():
        print(x)
    return f2
def foo(func):
    x=2
    func()   # 此处调用 f1()会在f1()的作用域中查找x的值,不会在foo()作用域中查找,他们不属于同一个name space
foo(f1())

输出结果: 1

如果在调用函数之前已经对变量重新赋值,则修改生效:

x=1
def f1():
    def f2():
        print(x)
    return f2
def f3(func):
    x=2
    func()
x=3
f3(f1())    # 在调用此函数时,同一name space中的x已经被重新定义

输出结果: 3

如果在调用之后,再对同一name space中的变量值进行修改,则函数调用的值为修改之前的值:

x=1
def f1():
    def f2():
        print(x)
    return f2
def f3(func):
    x=2
    func()
f3(f1())
x=3

输出结果: 1

闭包函数

由上面作用域的规律,可以总结出在作用的范围,通过定义返回函数,可以固定参数的值,无论在程序的任何位置调用,都可以保证函数参数的值不变,这种功能的函数就叫做闭包函数,为方便外部的函数调用,使用return的方式返回内部的函数对象:

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

推荐阅读更多精彩内容