Python学习笔记(八):函数

Python学习笔记(八):函数

关于函数

  • Python学习笔记(八):函数
  • 一.参数传递机制
    • 值传递
    • 引用传递
  • 二.变量作用域
    • 局部变量
    • 全局变量
    • 指定作用域范围中的变量
  • 三.函数用法和lambda表达式
    • 局部函数及用法
    • 函数使用方法
    • lambda表达式

一.参数传递机制

值传递

当系统开始执行函数时,系统对形参执行初始化,是把实参的值赋给函数的形参,在函数中操作的并不是实际的实参变量

a = 10
b = 16
def swap(a , b) : # 该函数实现交换a、b变量的值
    a, b = b, a
    print("在函数里经过交换后,a的值是",a,"b的值是",b)
    
swap(a , b)
print("执行函数之后,变量a的值是",a,"变量b的值是",b)

在函数里经过交换后,a的值是 16 b的值是 10
执行函数之后,变量a的值是 10 变量b的值是 16

程序中实际定义的变量 a 和 b,并不是 swap()函数里的 a 和 b 

Python学习笔记(八):函数_第1张图片

 1. 程序开始定义了 a、b 两个变量

 2. 当在主程序中调用swap()函数时,系统分别为主程序和swap()函数分配两块栈区,用于保存它们的变量

 3. 将主程序中的a、b变量作为参数值传入swap()函数,实际是在swap() 函数栈区中重新产生了两个变量a、b,并将主程序栈区中a、b 变量的值分别赋值给 swap()函数栈区中的a、b参数

 4. 系统存在两个a变量、两个b变量,存在于不同的栈区

 5. 在swap()函数中交换a、b两个变量的值,实际上是对swap()函数栈区的a、b 变量进行交换,交换结束后,输出swap() 函数中a、b变量的值

 6. 主程序栈区中 a、b 的值并未有任何改变,改变的只是swap()函数栈区中 a、b 的值

引用传递

参数的数据类型是可变对象(列表、字典),则函数的参数采用引用传递

引用传递方式的底层实现,采用的还是值传递

a_dict = {
     'a': 10, 'b': 16}

def swap(a_dict):
    a_dict['a'],a_dict ['b'] =a_dict ['b'], a_dict['a'] #实现字典的a、b两个元素的值交换
    print("swap函数里,a的值是",a_dict['a'], "b的值是", a_dict['b'])

swap(a_dict)
print("交换结束后,a的值是",a_dict['a'], "b的值是", a_dict['b'])

swap函数里,a的值是 16 b的值是 10
交换结束后,a的值是 16 b的值是 10

在执行swap()函数后 a、b 的值被交换,主程序中字典的a、b的值也被交换了

Python学习笔记(八):函数_第2张图片


 - 创建了一个字典对象,并定义了一个a_dict引用变量(指针)指向字典对象,此时内存中:对象本身和指向该对象的引用变量

 - 主程序调用swap()函数,把a_dict变量作为参数传入swap()函数,采用值传递

 - 主程序中的a_dict是一个引用变量(指针),保存了字典对象的地址值,值传递后让swap()函数的a_dict参数也保存这个地址值,引用到同一个字典对象图 

 - swap()函数中a_dict只是一个引用变量,实际操作的还是字典对象,主程序和swap() 函数引用的是同一个字典对象。所以在swap()函数中交换字典对象的 a、b的值后,主程序中所引用字典对象的a、b的值也被交换
  • 在 Python 函数中对参数直接使用“=”符号赋值并不能改变参数

  • 通过把数据包装成列表、字典等可变对象,然后把可变对象作为参数传入函数,在函数中通过列表、字典的方法修改它们,从而改变这些数据

二.变量作用域

作用域(Scope),变量的有效范围,就是变量可以在哪个范围内使用
变量的作用域由变量的定义位置决定,在不同位置定义的变量,作用域不一样

局部变量

局部变量(Local Variable)
在函数内部定义的变量,作用域仅限于函数内部

def test():
    name = "youchanwill"
    print("函数内部",name)
test()
print("函数外部",name)

函数内部 youchanwill
NameError: name 'name' is not defined #在函数外部访问其内部定义的变量,解释器会报NameError错误

当函数被执行时,会为其分配临时的存储空间,所有在函数内部定义的变量,都会存储在这块空间中
在函数执行完后,临时存储空间会被释放,其内部定义的变量会被销毁并回收


def test(name):
    print("函数内部",name)
test("youchanwill")
print("函数外部",name)

函数内部 youchanwill
NameError: name 'name' is not defined

函数的参数也属于局部变量,只能在函数内部使用
*Python解释器逐行运行程序代码

全局变量

全局变量(Global Variable)
在所有函数的外部定义变量

在函数体外定义的变量,一定是全局变量
在函数内部定义全局变量,使用global关键字对变量进行修饰后,该变量就会变为全局变量

def test():
	global name
    name = "youchanwill"
    print("函数内部",name)
test()
print("函数外部",name)
函数内部 youchanwill
函数外部 youchanwill

使用global关键字修饰变量名时,不能直接给变量赋初值,否则会引发语法错误

指定作用域范围中的变量

获取某个作用域内(全局范围或局部范围)所有的变量

globals()

返回一个包含全局范围内所有变量的字典,该字典中的每个key-value对,key为变量名,value为该变量的值

def test():
    name = "youchanwill"
    print("函数内部",name)
print(globals())
{
     .... 'test': <function test at 0x02A15810>....}

globals() 函数返回的字典中,会默认包含有很多变量,都是Python主程序内置的

通过该字典,还可以访问指定变量,如果需要,还可以修改值

name = 'you'
print(globals()['name'])
globals()['name'] = "youchanwill"
print(name)
you
youchanwill
locals()

到一个包含当前作用域内所有变量的字典,在函数内部调用locals()函数,会获得包含所有局部变量的字典,在全局范围内调用功能和globals()函数相同

name1 = 'you'
def test():
    name = "youchanwill"
    print(locals())
test() 
print(locals())
{
     'name': 'youchanwill'}
{
     ... 'name1': 'you', 'test': <function test at 0x02995810>...}

使用locals()函数获取所有全局变量时,和globals()函数一样,其返回的字典中会默认包含有很多变量

使用locals() 函数获得所有局部变量组成的字典时,可以像globals()函数那样通过指定键访问对应的变量值,但无法对变量值做修改
vars() 

返回一个指定object对象范围内所有变量组成的字典,如果不传入object参数则和locals()的作用完全相同

name1 = 'you'
class test:
    name = "youchanwill"
print(vars(test))
print(vars())
{
     ...'name': 'youchanwill'...}
{
     ... 'name1': 'you'...}(class): 用来描述具有相同的属性和方法的对象的集合,后续会学习到

三.函数用法和lambda表达式

局部函数及用法

在函数内部定义函数,此类函数称为局部函数


def outdef (): #全局函数
    def indef():  #局部函数
        print("youchanwill")
    indef()    #调用局部函数
outdef() #调用全局函数
youchanwill

默认情况下局部函数只能在其所在函数的作用域内使用
通过将局部函数作为所在函数的返回值,可以扩大局部函数的使用范围

def outdef (): #全局函数
    def indef():  #局部函数
        print("youchanwill")
	return indef #局部函数作为返回值
new_indef = outdef() #调用全局函数中的局部函数
new_indef()
youchanwill

所在函数没有返回局部函数,局部函数的可用范围仅限于所在函数内部

所在函数将局部函数作为返回值,则局部函数的作用域就会扩大,可以在所在函数的作用域中使用

def outdef ():  #全局函数
    name = "所在函数中定义的 name 变量"
    def indef(): #局部函数
        print(name)
        name = "局部函数中定义的name变量"
    indef()
outdef() #调用全局函数
UnboundLocalError: local variable 'name' referenced before assignment

局部函数中定义的变量遮蔽了所在函数中定义的变量

indef()函数中name变量的定义位于print()输出语句之后,导致 print(name) 语句在执行时找不到定义的name变量
使用nonlocal关键字解决上述问题

def outdef ():  #全局函数
    name = "所在函数中定义的 name 变量"
    def indef(): #局部函数
        nonlocal name   #使用nonlocal关键字
        print(name)
        name = "局部函数中定义的name变量"
    indef()
outdef() #调用全局函数
所在函数中定义的 name 变量

函数使用方法

直接将函数赋值给其它变量,在程序中可以用其他变量来调用该函数,更加灵活

def a_def ():
    print("执行a_def函数")
b_def = a_def #将函数赋值给其他变量   
b_def() #间接调用a_def() 函数
执行a_def函数
支持将函数以参数的形式传入其他函数中

def add (a,b):
    return a+b
def multi(a,b):
    return a*b
def a_def(a,b,add_multi):
    return add_multi(a,b)
   
print(a_def(10,16,add))#求 2 个数的和
print(a_def(10,16,multi)) #求 2 个数的乘积
26
160

通过使用函数作为参数,可以在调用函数时动态传入函数,实现动态改变函数中的部分实现代码,在不同场景中赋予函数不同的作用
支持函数的返回值也为函数,通过返回值为函数的形式,可以扩大局部函数的作用域

def outdef (): #全局函数
    def indef():  #局部函数
        print("youchanwill")
	return indef #局部函数作为返回值
new_indef = outdef() #调用全局函数中的局部函数
new_indef()
youchanwill

lambda表达式

lambda表达式(匿名函数)常用来表示内部仅包含 1 行表达式的函数
如果一个函数的函数体仅有1行表达式,就可以用 lambda 表达式来代替

name = lambda [list] : 表达式

定义lambda 表达式,必须使用lambda 关键字
[list] 为可选参数,等同于定义函数是指定的参数列表
value 为该表达式的名称

该语法格式转换成普通函数的形式:

def name(list):
    return 表达式
name(list)
def multi(a,b):
    return a*b
print(multi(10,16))

multi = lambda x,y:x*y
print(multi(10,16))

lambda 表达式,就是简单函数的简写版本

  • 对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁

  • 对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能

你可能感兴趣的:(Python,Note,python)