函数

一、函数定义及调用

  • 函数:对功能和动作的封装
  • 使用def关键字来定义函数
  • 使用"函数名()"可调用函数
def 函数名():
    函数体
函数名() # 调用函数

1.函数名

  • 函数名就是变量名,其命名规范与变量名命名规范一致
  • 函数名存储的是函数的内存地址
def func():
    pass
print(func) # <function func at 0x0000023A55019A60>
  • 函数名可以赋值给其他变量
def func():
    print("Hello World!")

ret = func
ret()  # Hello World!
  • 函数名可以当做容器类的元素
def func_1():
    print("-----1-----")

def func_2():
    print("-----2-----")

def func_3():
    print("-----3-----")

def func_4():
    print("-----4-----")

lst = [func_1, func_2, func_3, func_4]
for i in lst:
    i()

结果:
-----1-----
-----2-----
-----3-----
-----4-----
  • 函数名可以为函数的参数
def func_1():
    print("-----1-----")

def func_2():
    print("-----2-----")

def func(fn):
    fn()

func(func_1)  # -----1-----
  • 函数名可以为函数的返回值
def func():
    def func_1():
        print("-----func_1-----")
    return func_1

func()()  # -----func_1-----

 

打印函数名

def func():
    def func_1():
        print("-----func_1-----")
    return func_1

print(func.__name__)  # func

 

二、return

    执行完函数后,可以使用return来返回结果

  • return作用:终止函数运行
  • 如果函数体无return,则调用函数返回None
  • 如果函数体有return,但return后未有值,则返回None
  • 如果函数体有return,且return后有一个值或变量名,则返回值或变量名所指向的值
  • 如果函数体有return,且return后有多个值,则多个值以元组形式返回给调用者,调用者可直接解构成多个变量
def operation(a, b):
    sum = a + b
    sub = a - b
    qud = a * b
    qut = a / b
    return sum, sub, qud, qut

x, y, z, w = operation(1, 2)
    

三、参数

1.形参

    写在函数声明的位置的变量

1) 位置参数

def regist(id, name, age, gender):
    print(id, name, age, gender)

regist(1, "Tom", 18, "")  # 1 Tom 18 男

2) 默认值参数

    默认值参数可以把函数共性的参数问题进行提炼,以减少输入,提高输入效率

def regist(id, name, age, gender=""):
    print(id, name, age, gender)

regist(1, "Tom", 18) # 1 Tom 18 男

3) 混合参数(位置参数+默认值参数)

    位置参数在前,默认值参数在后,否则报错

def regist(id, name, gender="", age):
    print(id, name, age, gender)

regist(1, "Tom", 18) # SyntaxError: non-default argument follows default argument

4) 动态参数

a.动态接收位置参数——*args

  • *表示动态传参,可以接受所有的位置参数
  • 传参的时候自动的把实参打包成元组,交给形参
  • 动态传参可以不传参数
def func(*args):
    print(args)

func(11, 22, 33, 44, 55, 66)  # (11, 22, 33, 44, 55, 66)
def func(*args):
    print(args)

func()  # ()

 

b.动态接收关键字参数——**kwargs

  • 接收到的内容放在字典里
def func(**kwargs):
    print(kwargs)


func(a=11, b=22, c=33, d=44, e=55) # {'a': 11, 'b': 22, 'c': 33, 'd': 44, 'e': 55}

 

5) 形参顺序

顺序:位置参数,*args,默认值参数,**kwargs

def func(a, *args, b="", **kwargs):
    print(a, args, b, kwargs)


func(11, 22, 33, 44, b="", c=66, d=77,) # 11 (22, 33, 44) 男 {'c': 66, 'd': 77}

 

6)打散

  • * + string/list/
print(*[1, 2, 3, 4, 5, 6]) # 1 2 3 4 5 6
  • ** + dict
def func(**kwargs):
    print(kwargs)

func(**{"name": "Tom", "age": 18, "hobby": "football"})  # {'name': 'Tom', 'age': 18, 'hobby': 'football'}

 

7)无敌传参

def func(*args, **kwargs):
    print(args, kwargs)


func(11, 22, 33, 44, a=55, b=66, c=77, d=88)  #(11, 22, 33, 44) {'a': 55, 'b': 66, 'c': 77, 'd': 88}

 

2.实参

    在函数调用的时候给函数传递的值。实际执行的时候给函数传递的信息

1) 位置参数

    按照形参顺序给把各实参赋值给相应的形参

def introduction(name, age):
    print("My name is %s, I'm %s years old." % (name, age))

introduction("Tom", 18)  # My name is Tom, I'm 18 years old.
def introduction(name, age):
    print("My name is %s, I'm %s years old." % (name, age))

introduction(18, "Tom")  # My name is 18, I'm Tom years old.

2)关键字参数

    根据形参声明的变量名来传递信息,关键字实参不需要考虑形参顺序

def introduction(name, age):
    print("My name is %s, I'm %s years old." % (name, age))

introduction(age=18, name="Tom") # My name is Tom, I'm 18 years old.

3)混合参数(位置参数+关键字参数)

    位置参数在前,关键字参数在后,否则报错


def introduction(name, age, sex):
print("My name is %s, I'm %s years old %s" % (name, age, sex))

introduction("Tom", sex="boy", age=18) # My name is Tom, I'm 18 years old boy

 

def introduction(name, age, sex):
    print("My name is %s, I'm %s years old %s" % (name, age, sex))

introduction("Tom", sex="boy", 18) # SyntaxError: positional argument follows keyword argument

 

3.传参

    给函数传递信息的时候将实际参数交给形式参数的过程

四、命名空间和作用域

1.命名空间

  • 内置命名空间:存放python解释器为我们提供的名字,list,tuple,str,int这些都是内置命名空间
  • 全局命名空间:py文件中,函数外声明的变量都属于全局命名空间
  • 局部命名空间:在函数中声明的变量会放在局部命名空间
  • 加载顺序:内置命名空间--->全局命名空间--->局部命名空间(函数被执行的时候)
  • 取值顺序:局部命名空间--->全局命名空间--->内置命名空间

2.作用域

  • 全局作用域:全局命名空间 + 内置命名空间
  • 局部作用域:局部命名空间
  • 变量可从局部向全局寻找,但不可从全局向局部寻找

3.locals() 和 globals()

  • locals():查看当前作用域中的名字,如果在函数中调用locals(),则查看局部作用域中的名字,如果在函数外调用locals(),则查看全局作用域中的名字
  • globals():查看全局作用域中(内置+全局)中的名字

4.global 和 nonlocal

1) global

  • 如果函数内部未引入全局变量,则函数可以使用全局变量,但无法修改
a = 10

def func():
    b = a + 10
    print(a)
    print(b)

func()  # 10 20
  • 如果利用global在函数内引入全局变量,则在函数内部可对全局变量进行修改
a = 10

def func():
    global a
    a = 20
    print(a)

func()
print(a)  # 20 20
  • 如果利用global在函数内部引入全局变量,而函数外无此变量,则此局部变量升华为全局变量,即此变量为全局变量
def func():
    global a
    a = 20
    print(a)

func()
print(a)  # 20 20 

2) nonlocal

  • 在局部命名空间,引入上一层名称空间中的名字,如果上一层没有,继续往上一层中寻找,如果整个局部命名空间都无,则报错
def func1():
    a = 10
    def func2():
        nonlocal a
        a = 20
        print(a)
    print(a)
    func2()
    print(a)

func1() # 10 20 20

五、函数嵌套

  • 函数内部可以嵌套函数
  • 每一层都会产生独自的名称空间,在寻找变量时,则为向上一层一层寻找。
def func1():
    a = 10
    def func2():
        def func3():
            nonlocal a
            a = 20
        print(a)
        func3()
    print(a)
    func2()
    print(a)

func1()  # 10 10 20 

 六、闭包

    内层函数对外层函数的变量的引用

作用:

  • 保护变量不受侵害
  • 可以让一个变量常驻内存
def outer():
    name = "Tom"
    def inner():
        print(name)
    inner()

outer() # Tom
    

 1.检测函数是否为闭包

    可以使用__closure__来检测函数是否为闭包

  • 如果返回cell,则为闭包
  • 如果返回None,则不是闭包
def outer():
    name = "Tom"
    def inner():
        print(name)
    inner()
    print(inner.__closure__)

outer()


结果:
Tom
(<cell at 0x000001F751868588: str object at 0x000001F7518F80A0>,)

2.变量常驻内存说明

    函数外边调用内部函数:

def outer():
    name = "Tom"
    def inner():
        print(name)
    return inner

ret = outer()
ret()  # Tom

     如果一个函数执行完毕,则这个函数中的变量以及局部命名空间中的内容都将会被销毁。但由于外界可以通过ret()去访问内部函数。那这个时候内部函数访问的时间和时机就不一定了。如果此时,闭包中变量被销毁了,那么内部函数将不能正常执行。所以,Python规定,如果在内部函数中访问了外层函数的变量,那么这个么变量将不会消亡。

posted @ 2018-10-29 16:06  Ethan_Y  阅读(229)  评论(0编辑  收藏  举报