函数

函数

数学定义:y=fx),yx的函数,x是自变量

Python函数

有若干个语句块,函数名称,参数列表构成,它是组织代码的最小单元

完成一定作用

函数的作用

结构化编程对代码的最基本的封装,一般按照功能组织一段代码

封装的目的为了复用,减少了冗余代码

代码更加简洁美观,更加易读

函数的分类

内建函数,如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)

上面只是一个函数的定义,有一个函数叫做add,接收2个参数

计算的结果,通过返回值返回

调用的通过函数名add2个参数,返回值可使用变量接受

定义需要在调用前,也就是说调用时,已经被定义过了,否者Nameerror异常

函数参数

参数调用时传入的参数要和定义的个数匹配(可变参数例外)

位置参数

def f(x,y,z)调用使用f(1,3,5)

按照定义顺序传入实参

关键字参数

def f(x,y,z)调用使用f(x=1,y=3,z=5)

使用形参的名字来出入实参的方式,如果使用了形参名字,那么顺序可以改变

传参

f(z=None,y=10,x=[1])

f((1),z=6,y=4.1)

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

函数参数默认值

参数默认值:定义时,在形参后跟上一个值

def ad(x=4,y=5):

return x+y

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

add(x=5,y=6),add(y=5,x=6)

测试def add(x=4,y)

作用

参数的默认值可以在未传入足够的实数参数的时候,对没有给定的参数赋值为默认值

参数非常多的时候,并不需要用户每次都输入所有的数,简化函数调用

举例

定义一个函数login,参数名为hostportusernamepasswd

def login(host=’172.0.0.1′,port=’8080′,username=’wayne’,passwd=’123′):

    print(‘{}:{}@{}/{}’.format(host,port,username,passwd))

login(‘127.0.0.1′,’9999′,’zm’,’zhangmeng’)

可变参数

问题:有多个参数,需要累加求和

def add(nums):

    sum = 0

    for x in nums:

        sum += x

    return sum

add([1,3,5])

在形参前使用*表示该形参是可变参数,可以接收多个实参

收集多个实参为一个tuple

关键字参数的可变参数

配置信息打印

def showconfig(**kwargs):

for k,v in kwargs.items():

Print(‘{} = {}’.format(k,v))

showconfig(host=’127.0.0.1′,port=’8080′,username=’zm’,passwd=’123′)

形参前使用**符号,表示可以接收多个关键字参数

收集的实参名称和值组成一个字典

总结

有位置可变参数和关键字可变参数

位置可变参数在形参前使用一个*

关键字可变参数在形参前使用两个**

位置可变参数和关键字可变参数都可以收集若干个实参,位置可变参数收集形成一个元组,关键字可变参数搜集可以形成一个字典

混合使用参数时候,可变位置参数要放到参数裂变的最后,普通位置参数需要放到参数列表的前面,位置可变参数需要在关键字可变参数之前

举例:

def fn(x,y,*args,**kwargs):

    print(x)

    print(y)

    print(args)

    print(kwargs)

fn(3,5,7,9,10,a=1,b=’python’)

fn(3,5)

fn(3,5,7)

Keyword-only参数(python3加入)

如果在一个*参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,而是Keyword-only参数

def fn(x,*kwargs):

    print(x)

    print()

fn(5,5)

fn(3,5,7)

fn(3,5,x=7)#错误

如果fn的参数换位置,则x永远得不到值,所以报错

Keyword-only参数另一种形式

def fn(*,x,y):

Print(x,y)

fn(x=5,y=6)

*号之后,普通形参都变成了必须给出的Keyword-only参数

def fn(y,*args,x=5):

    print(‘x={},y={}’.format(x,y))

    print(args)

fn()

fn(5)

fn(x=6)

fn(1,2,3,x=10)

fn(y=17,2,3,x=10)

xeyword-only参数

参数解构

def add(x,y):

    return x+y

add(4,6)

add(*[4,5])

add(*(4,5))

add(*{4,5})

add(*range(1,3))

给函数提供实参的时候,可以在集合类型钱使用*或者**,把集合类型的结构解开,提取出所有元素作为函数的实参

非字典类型使用*解构成位置参数

字典类型使用**解构成关键字参数

提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配

def add(x,y):

    return x+y

add(*(4,5))

add(*[4,5])

add(*(4,6))

d = {‘x’:5,’y’:6}

add(**d)

add(**{‘x’:5,’y’:6})

参数解构和位置可变参数

给函数提供实参的时候,可以在集合类型前使用*或者**,吧集合类型的结构解开,提取出所有元素作为函数的实参

def add(*nums):

    res = 0

    for x in nums:

        res += x

    return res

add(1,2,3)

add(*[1,2,3])

add(*range(10))

上三角打印

def show(n):

    tail = ‘ ‘.join([str(i) for i in range(n,0,-1)])

    width = len(tail)

    for i in range(1,n):

        print(“{:>{}}”.format(” “.join([str(j) for j in range(i,0,-1)]),width))

    print(tail)

show(12)

下三角打印

def showtail(n):

    tail = ” “.join([str(i) for i in range(n,0,-1)])

    print(tail)

    for i in range(len(tail)):

        if tail[i] == ‘ ‘:

            print(‘ ‘*i,tail[i+1:])

showtail(12)

组合打印

def trangle(n):

    for i in range(1,n+1):

        for j in range(n,0,-1):

            if i<j:

                print(‘ ‘*len(str(j)),end = ‘ ‘)

            else:

                print(j,end = ‘ ‘)

        print()

    tail = ” “.join([str(i) for i in range(n,0,-1)])

    print(tail)

    for i in range(len(tail)):

        if tail[i] == ‘ ‘:

            print(‘ ‘*i,tail[i+1:])

trangle(12)    

Python函数返回值,作用域

函数的返回值

举例:

def showplus(x):

    print(x)

    return x+1

showplus(5)

举例:

def showplus(x):

    print(x)

    return x+1

    print(x+1)#并不会执行  ruturn直接终止了

showplus(5)

多条return语句

def guess(x):

    if x > 3:

        return ‘>3’

    else:

        return ‘<=’

print(guess(10))

多条return语句

def showpuls(x):

    print(x)

    return x+1

    return x+2

showplus(5)

举例:

def fn(x):

    for i in range(x):

        if i > 3:

            return i

    else:

        print(‘{} is not greater than 3’.format(x))

print(fn(5))

print(fn(3))

函数的返回值总结

Pyhton函数使用return语句返回‘回值’

所有函数都有返回值,如果没有return语句,隐式调用returnNone

Return语句并不一定是函数的语句块的最后一条语句

一个函数可以存在多条return语句,但是只有一条可以被执行,如果没有return被执行,隐式调用return None

如果有必要,可以显示调用eturnNone,可以简写为return

如果函数执行的return语句,函数就会返回,当前被执行的return语句之后其他语句就不会被执行了

作用:结束函数调用,返回值

返回多个值

函数不能同时返回多个值

return [1,3,5]是指明返回一个列表,是一个列表对象

return 1,3,5 看似返回多个值,隐式的被python封装成了一个元组

def showlist():

    return 1,3,5

x,y,z = showlist()

print(x,y,z)

函数嵌套

在一个函数中定义了另外一个函数

def outer():

    def inner():

        print(‘inner’)

    print(‘outer’)

    inner()

outer()

函数有可见范围,这就是作用域的概念

内部函数不能被外部直接使用,就会抛NameError异常

作用域

一个标识符的可见范围,就是标识符的作用域。一般说的是变量的作用域

例子:

x = 5

def foo():

    print(x)

foo()

 

x = 5

def foo():

    x += 1

    print()

foo()

全局作用域

在整个程序运行环境中都可见

局部作用域

在函数,类等内部可见

局部变量使用范围不能超过其所在的局部作用域

例子;

def fn():

    x = 1  #局部可见在fn

def fn2():

    print(x)#不可见

#print(x)

fn2()

嵌套例子:

def outer1():

    o = 65

    def inner():

        print(‘inner {}’.format(o))

        print(chr(o))

    print(‘outer {}’.format(o))

    inner()

outer()

 

 

def outer2():

    o = 65

    def inner():

        o = 97

        print(‘inner {}’.format(o))

        print(chr(o))

    print(‘outer {}’.format(o))

    inner()

outer()

从嵌套例子可以看出外层变量作用域在内层可见

内层作用域inner,如果定义了o=97,相当于作用域中重新定义了一个新的变量o但这个o并没有覆盖外层作用域中outero

全局变量global

使用全局作用域中必须有x的定义

使用global关键字的变量,将foo内的x声明为使用外部的全局作用域中定义的x

例子

def foo():

    global x

    x =10

    x += 1

    print(x)

print(x)

但是,x=10赋值即定义,x在内部作用域作为一个外部作用域的变量赋值,所以x+=1不会报错,这里的x的作用域还是全局的

global总结

X +=1 这种特殊形式产生错误的原因,先引用后赋值,而python动态语言是赋值才算是定义才能被引用,解决办法,在这一条语句前增加x=0之类的赋值语句,或者使用global告诉内部作用域,去全局作用域查找变量定义

内部作用域使用x=5之类的赋值语句会重新定义局部作用域使用的变量x,但是,一旦这个作用域中使用global使用x为全局的,那么x=5相当于在为全局作用域的变量赋值

globa使用原则

外部作用域变量会内部作用域可见,但也不要在这个内部的局部作用域中直接使用因为函数的目的就是为了封装尽量与外界隔离

如果函数需要使用外部全局变量,请使用函数的形参传参解决

不用globa学习他就是为了深入理解变量的作用域

闭包

自由变量:未在本地作用域中定义的变量。例如定义在内存函数外的外层函数的作用域中的变量

闭包:就是一个概念,出现在嵌套函数中。指的是,内层函数引用到了外城函数的自用变量就形成了闭包,很多语言都有这个概念,最熟悉的就是JavaScript

def counter():

    c = [0]

    def inc():

        c[0] += 1

        return c[0]

    return inc

foo = counter()

print(foo(),foo())

c = 100

print((foo()))

nonlocal关键字

使用了nonlocal关键字,将变量标记为不再本地作用域定义。而在上级某一级局部作用域中定义但不能是全局作用域中定义

count是外层函数的局部变量,被内部函数引用

内部函数使用nonlocal关键字声明count变量在上级作用域而非本地作用域中定义

1. 可以正常使用,且形成了闭包

2. 不能正常运行,变量a不能再全局作用域中

1def conter():

     count = 0

     def inc():

         nonlocal count

        count += 1

        return count

foo = counter()

foo()

foo()

2a = 50

def counter():

    nonlocal a

    a += 1

    print(a)

    count = 0

    def inc():

        nonlocal count

        count += 1

        return count

    return inc

foo = counter()

foo()

foo()

默认值的作用域

def foo(xyz=[]):

    xyz.append(1)

    print(xyz)

foo()

foo()

print(xyz)#报错,当前作用域没有xyz变量

函数也是对象,python吧函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期

查看foo.__defaults__属性

def foo(xyz=[],u=’abc’,z=123):

    xyz.append(1)

    return xyz

print(foo(),id(foo))

print(foo.__defaults__)

print(foo(),id(foo))

print(foo.__defaults__)

__defaults__属性中使用的元素组保存所有位置参数默认值,他不会因为在函数体内使用了它而发生改变

Xyz都是传入参数或者默认的参数的副本,如果想修改原参数,无能为力

如果缺省值为None就创建一个醒的列表

第一种方法

使用影子拷贝创建一个新的对象,永远不能改变传入的对象

第二种方法

通过值得判断就可以灵活的选择创建对象或则修改传入对象

这种方式灵活,应用广泛

很多函数的定义,都可以看到使用None这个不可改变的值作为默认参数,可以说这是一种惯用法

函数的销毁

def foo(xyz=[],u=’abc’,z=123):

    xyz.append(1)

    return xyz

print(foo(),id(foo),foo.__defaults__)

def foo(xyz=[],u=’abc’,z=123):

    xyz.append(1)

    return xyz

print(foo(),id(foo),foo.__defaults__)

del foo

print(foo(),id(foo),foo.__defaults__)

全局函数销毁

重新定义同名函数

del语句是删除函数对象

程序结束时

 

 

 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/96261

发表评论

登录后才能评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1823388528@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班