函数

2018-08-22  本文已影响0人  秋幻旎苏

Python 中的函数是由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元,可以完成一定的功能

一.函数的作用

二.函数的分类

三.函数定义、调用

1.def关键字定义函数

def 函数名(形参列表):
    函数体(代码块)
    [return 返回值]

2.函数调用

关键字传参必须放在最后

3.函数形参

①位置参数
② 参数默认值(缺省值)

在定义形参的时候可以给形参赋予一个默认值.

def fn(x=3,y=2):
    print("x={},y={}".format(x,y))
③可变位置参数
④keyword-only参数(python3 后加入)
⑤ 可变关键字参数
⑥总结

函数参数解构

参数解构.gif

四. 函数嵌套

在一个函数中定义了另外一个函数,内部的函数不能在外部直接使用,会抛出NameError 异常。
函数有可见范围,这就是作用域的概念


函数嵌套.gif

1.作用域

def outer2():
    o = 65
    def inner():
        o = 97
        print("inner {}".format(o))
    print("outer {}".format(o))
    inner()
outer2()

#结果
#outer 65
#inner 97

通过上述嵌套结构例子可以看出

①.全局变量globle
x = 5
def foo():
##如果不使用global,会出现先引用后赋值的异常报错
    global x 
    x += 1 
    print("x =",x)
foo()
print("x =",x)
###结果
#x = 6
#x = 6
x = 5
def foo():
    global x
    x += 1
    print("x =",x)
    x = 9
foo()
print("x =",x)

##结果
#x = 6
#x = 9

globle 使用原则

不要用global,学习它,只是为了深入理解变量作用域!!!

对“作用域”可以进行如下理解:
1.在最顶层,比如shell层,有一个符号表会跟踪记录这一层所有的名称定义和绑定
2.调用函数的时候,会建立一个新的符号表(常称为栈帧)。这个表跟踪记录函数中所有的名称定义(包括形参)和它们当前的绑定。如果函数体内又调用了一个函数,就再建立一个栈帧。
3.函数结束时候,它的栈帧也随之消息。

2.闭包

def counter():
    c = [0]
    def inc():
        c[0] += 1  #应用的是自由变量正式counter的变量c
        return c[0]
    print(c[0])
    return inc
  
#counter()()
foo = counter()
print(foo(),foo())   #调用的是inner()
print(foo())

这是python2 实现闭包的方式,python3 还可以使用nonlocal 关键字

①nonlocal 关键字

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

def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc
foo = counter()
print(foo())
print(foo())
②默认值的作用域
def foo(xyz=[]):
    xyz.append(1)
    print(xyz)
foo()
foo()

###result
#[1]
#[1, 1]
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__)

非引用类型例子

def foo(w,u='abc',z=123):
    u = 'xyz'
    z = 789
    print(w,u,z)
print(foo.__defaults__)
foo('wing')
print(foo.__defaults__)

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

def foo(w,u='abc',*,z=123,zz=[456]):
    u = 'xyz'
    z = 789
    zz.append(1)
    print(w,u,z,zz)
print(foo.__defaults__)
foo('wing')
print(foo.__kwdefaults__)

1.函数体内,不改变默认值

def foo(xyz=[],u='abc',z=123):
    xyz = xyz[:]     #影子拷贝
    xyz.append(1)
    print(xyz)
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])    
foo()
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)

2.使用不可变类型的默认值

def foo(xyz=None,u='abc',z=123):
    if xyz is None:
        xyz = []
    xyz.append(1)
    print(xyz)
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])    
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)

3.总结

四.变量名解析原则LEGB

五.函数的销毁

全局函数销毁

局部函数销毁

五.文档字符串:

""" text """
三引号之间的文本在Python中称为文档字符串。按照惯例,使用文档字符串提供函数的规范。可以使用内置的函数help访问这些字符串。

文档字符串.gif

六.递归

2.定义

** 函数直接或者间接调用自身就是递归**

2.递归要求

3.递归的性能

4.间接递归:

def foo1():
    foo2()
def foo2():
    foo1()
foo1()

间接递归,是通过别的函数调用了函数自身。
但是,如果构成了循环递归抵用是非常危险的,但是往往这种情况在代码复杂的情况下,还是可能发生这种调用。要用代码的规范来避免这种递归调用的发生。

5.递归总结

七.匿名函数

print((lambda :0)())
print((lambda x,y=3:x+y)(5))
print((lambda x, y=3: x + y)(5, 6))
print((lambda x, *, y=30: x + y)(5))
print((lambda x, *, y=30: x + y)(5, y=10))
print((lambda *args: (x for x in args))(*range(5)))
print((lambda *args: [x+1 for x in args])(*range(5)))
print((lambda *args: {x+2 for x in args})(*range(5)))
[x for x in (lambda *args: map(lambda x: x+1, args))(*range(5))] 
[x for x in (lambda *args: map(lambda x: (x+1,args), args))(*range(5))]
上一篇下一篇

猜你喜欢

热点阅读