Python 3 教程 在线

1128Python3 函数

函数也可以以一个函数为其参数:

def hello () :
  print ("Hello, world!")

def execute(f):
  "执行一个没有参数的函数"
  f()

execute(hello)

输出:

Hello, world!

1127Python3 函数

函数内可以访问全局变量,但不能更新(修改)其值!

例 :

a = 10
def sum ( n ) :
   n += a
   print ('a = ', a, end = ' , ' )
   print ( 'n = ', n )
  
sum(3)

输出 :

a =  10 , n =  13

如果引用了还没更新的值则会报错 :

a = 10
def sum ( n ) :
   n += a
   a = 11
   print ('a = ', a, end = ' , ' )
   print ( 'n = ', n )
  
sum(3)

输出 :

...
UnboundLocalError: local variable 'a' referenced before assignment

可以加上 global 引用以更新变量值 :

a = 10
def sum ( n ) :
   global a
   n += a
   a = 11
   print ('a = ', a, end = ' , ' )
   print ( 'n = ', n )

sum ( 3 )
print ( '外 a = ', a )

输出:

a = 11 , n = 13外 a = 11

1126Python3 函数

对于变量作用域,变量的访问以 L(Local) –> E(Enclosing) –> G(Global) –>B(Built-in) 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

观察以下几个例子,均从内部函数输出变量 x:

1. 局部作用域

x = int(3.3)

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print(x)
    inner()

outer()

执行结果为 2,因为此时直接在函数 inner 内部找到了变量 x。

2.闭包函数外的函数中

x = int(3.3)

x = 0
def outer():
    x = 1
    def inner():
        i = 2
        print(x)
    inner()

outer()

执行结果为 1,因为在内部函数 inner 中找不到变量 x,继续去局部外的局部——函数 outer 中找,这时找到了,输出 1。

3.全局作用域

x = int(3.3)
x = 0
def outer():
    o = 1
    def inner():
        i = 2
        print(x)
    inner()

outer()

执行结果为 0,在局部(inner函数)、局部的局部(outer函数)都没找到变量 x,于是访问全局变量,此时找到了并输出。

4. 内建作用域

x = int(3.3)
g = 0
def outer():
    o = 1
    def inner():
        i = 2
        print(x)
    inner()

outer()

执行结果为 3,在局部(inner函数)、局部的局部(outer函数)以及全局变量中都没有找到变量x,于是访问内建变量,此时找到了并输出。

1125Python3 函数

关于可更改与不可更改类型, 以及其它语言的值类型与引用类型的介绍,一直一来感觉都不太严谨, 说法是否正确有待验证。

简单的说就是,不可更改类型传到函数里重新赋值后,两次输出值不一样,而可更改类型传到函数里对对象的"属性" 重新赋值后输出值一样。

这里照搬一下例子:

# 可写函数说明
def changeme( mylist ):
   "修改传入的列表"
   mylist.append([1,2,3,4])
   print ("函数内取值: ", mylist)
   return
 
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)

请注意:上面特意用了引号标准的部分,对可变类型或者引用的操作修改的是传过来的对象的属性。

可以这么理解(例子有点随意):我在画画,小明来了说他也要画,我让他和我一起画,他如果和我在同一个画板上画,那么我们两的画就会同时改变。 而如果他说不,我要另外用一块画板,然后重新拿了块画板画起来了,那么我们两的画自然就不一样了。

同理可更改类型 的属性进行操作,这只是对引用的内存块里面的值进行操作,引用并没变,自然所有引用它的对象的值都变了。而对不可更改的对象进行操作,因为它引用的内存块只是对应一个固定的值,不能进行修改,要重新复制实际上就是更新引用。

如果我们运行下面的例子,对可更改类型的引用进行修改,结果就不一样了。

# 可写函数说明
def changeme( mylist ):
   "修改传入的列表"
   mylist = [1,2,3,4]
   print ("函数内取值: ", mylist)
   return
 
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)

结果

函数内取值:  [1, 2, 3, 4]
函数外取值:  [10, 20, 30]

1124Python3 函数

lambda 匿名函数也是可以使用"关键字参数"进行参数传递

>>> g= lambda x,y : x**2+y**2
>>> g(2,3)
13
>>> g(y=3,x=2)
13

同样地,lambda 匿名函数也可以设定默认值

>>> g= lambda x=0,y=0 : x**2+y**2
>>> g(2,3)
13
>>> g(2)
4
>>> g(y=3)
9

注意:如果只打算给其中一部分参数设定默认值,那么应当将其放在靠后的位置(和定义函数时一样,避免歧义),否则会报错。