【Python学习笔记】六、函数

函数是组织好的,可复用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。

6.1函数的定义与调用

def函数名(形式参数列表):

     """文档字符串"""

     函数体

• 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。

• 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

• 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

• 文档字符串可以通过函数名._doc_访问,也可以通过内建的help函数获取

• 函数内容以冒号起始,并且缩进。

• return [表达式] 结束函数,return后的语句不会被执行。

• 通过return语句可以选择性地返回一个值(或元组)给调用方。函数没有return语句或是执行了不返回任何值的return语句相当于返回 None。

• 函数的调用:

函数名(实际参数列表)

6.2函数的参数

(1)形式参数与实际参数

•   函数定义时括弧内为形参(formal parameter),一个函数可以没有形参,但是括弧必须要有,这样表示该函数不接受参数

•   函数调用时向其传递实参(actual parameter),将实参的值或引用传递给形参

•   Python默认通过引用进行函数的参数传递,意味着不需要创建额外的拷贝就可以在程序中传递(很大的)对象,提高了效率,但是当参数传递像列表、字典这样的可变对象(mutable)时,函数中对可变对象参数的在原处的修改能够影响调用者(即改变实参)

• 如果不想要函数内部,对可变对象参数在原处的修改,影响外部,可以简单地创建一个可变对象的拷贝

(2)参数类型

①位置参数

• 调用函数时根据函数定义的参数位置来传递参数。

• 参数的顺序必须一一对应,且缺一不可

②默认值参数

def 函数名([形参名,] 形参名=默认值, ……) :

               函数体

• 默认值参数必须出现在函数参数列表的最右端,且任何一个默认值参数右边不能有非默认值参数。

• 调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以赋值,具有较大的灵活性

• 使用函数名._defaults_可以查看函数所有默认值参数的当前值,其返回值为一个元组

• 多次调用函数且不为默认值参数传递值时,默认值参数只在第一次调用时进行解释。对于列表、字典类型的默认值参数,这一点可能会导致难以发现的错误。使用“空列表”作为函数的默认值参数是危险的。应当设置成None。

• 当然,如果是对可变对象的赋值操作(这样的操作生成了新的对象),没有关系:

• 考虑这一点也可以写出具有“Local caches / memorization”的函数

 

③关键参数

•    关键参数指实参,即调用函数时的传入的参数

•    通过关键参数传递,实参顺序可以和形参顺序不一致,并不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦

④可变长度参数

(a)包裹参数

•    *parameter包裹位置参数:用来接受多个实参并将其放在一个元组中

•    **parameter包裹关键字参数:用来接受字典形式的实参

•    几种不同类型的参数可以混合使用,但这使得代码难懂,不要这样做

•    在调用函数时使用func(*parameter)和func(**parameter)可以执行相反的操作

(b)解包裹参数(参数解包)

•    func(*parameter): 为含有多个形参的函数传递实参时,可使用列表、元组、字典、集合以及其它可迭代对象作为实参,并在实参名称前加一个星号,Python解释器将自动进行解包,然后将序列中的元素传递给多个形参,此时相当于位置参数传递

•    如果使用字典对象作为实参,则默认使用字典的“键”

•    一定要保证实参中元素个数与形参个数相等,否则出错

•    func(**dict): 以“键-值”对的形式解包一个字典,此时相当于关键字参数传递,名字和函数定义的参数名必须要一一对应

6.3变量作用域

在代码中,变量起作用的范围称为变量的作用域。一个变量在函数外部定义和在函数内部定义,其作用域是不同的

(1)局部变量(local variable)

在函数内定义的变量只在该函数内起作用,称为局部变量。函数结束时,其局部变量被自动删除。

应当优先考虑使用局部变量。

(2)全局变量(global variable)

•函数外部定义的变量为全局变量

• 全局变量会被局部变量屏蔽,如果局部变量的名字和全局变量相同,在函数内部将不能直接访问全局变量。对同名局部变量的操作只在内部作用域(局部命名空间)起作用,并不影响外部(全局)作用域中的全局变量。

• 如果全局变量被局部变量屏蔽,可以使用函数globals()[‘parameter’]来获取全局变量值

• 如果要重绑定全局变量(为全局变量赋新值,并要将这个赋值结果反映到函数外),可以在函数内用global将其声明为全局变量。

 

•    在函数内部直接将一个变量声明为全局变量,而在函数外没有声明,在调用这个函数之后,将增加为新的全局变量

(3)命名空间(Namespace)

命名空间就是一个从名称到对象的映射。命名空间可以看作一个字典,键为变量名,值是变量对应的值。

• 各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。

• 在Python程序执行期间,按照解释器执行的状态,可以将命名空间划分为以下3类:

Local局部命名空间,函数所拥有的命名空间。记录了函数中定义的所有变量,包括函数的入参、内部定义的局部变量。在函数被调用时才被创建,但函数返回结果或抛出异常时被删除。(每一个递归函数都拥有自己的命名空间)。

Global全局命名空间,模块所拥有的命名空间。记录了模块中定义的变量,包括模块中定义的函数、类、其他导入的模块、模块级的变量与常量。在模块被加载时创建,通常一直保留直到python解释器退出。

Built-in内建命名空间,Python内建的命名空间。放着内置的函数和异常,任何模块均可以访问。在Python解释器启动时创建,一直保留直到解释器退出。

(4)作用域(Scope)

• 一个作用域是指一段程序的文本区域,可以是一个函数或一段代码。一个变量的作用域是指该变量的有效范围。

• Python的作用域是静态作用域,变量的作用域源于它在代码中的位置。

• 作用域按照变量的定义位置可以划分为4类:

Local(函数内部)局部作用域

Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)(见6.4)

Global(模块全局)全局作用域

Built-in(内建)内建作用域

x = int(10) #python内置作用域B

y = 2#当前模块中的全局变量G

defoutfuction():

   outfx = 2#外层作用域E

       def infunction():

            infx = 3#局部作用域L

• Python解释器动态执行过程中,当遇到对变量进行解释时,会按照LEGB-Rule的顺序在命名空间里从里到外地寻找“变量-对象”映射,从而确定该变量对应的作用域(因此会发生优先级高的变量屏蔽优先级低的同名变量的情况)。因为命名空间是动态创建的,所以变量对应的作用域也会动态变化。

• 所有命名空间查找完成没有找到对应的变量,则抛出 NameError: name 'xxxx' is not defined的异常。

• Python除了def/class/lambda 外,其他如: if/elif/else/ try/except for/while并不能改变其作用域。定义在他们之内的变量,外部还是可以访问。

• 一定要在定义global后才能给外部作用域变量赋值

i=1

def func2():

    i=i+1

func2();

#错误:UnboundLocalError: local variable 'i' referenced before assignment

 

你可能感兴趣的:(Python)