三、函数
1.如何避开变量作用域的陷阱
1)全局变量与局部变量
======================================================
>>> x = 100
>>> def func():
print('Inside func:x is {}'.format(x))
>>> func()
Inside func:x is 100
>>> print('x is still:{}'.format(x))
x is still:100
======================================================
这个比较好理解x是全局变量,作用域是整个文件,函数内部是可以引用的.
======================================================
>>> x1 = 100
>>> def func():
x1 = 10
print('Changed local x to :{}'.format(x1))
>>> func()
Changed local x to :10
>>> print('x1 is still:{}'.format(x1))
x1 is still:100
======================================================
大家看在函数外部有一个变量x1,在函数内部也有一个变量x1,这两个变量虽然名字长的一样,但是是完全不同的:
1.1.函数内部的是本地变量,它的生命周期只在函数内部,出了函数就结束了
1.2.而x1在函数外部模块文件中声明的(python一个文件也叫一个模块),是全局变量,不会被函数里面的局部变量影响,所以最后print的x1还是100
2)全局变量声明
======================================================
>>> x = 100
>>> def func():
global x #注意加了一个global关键字,表示x是全局作用域
print('x is:{}'.format(x))
x = 10
print('Changed local x to:{}'.format(x))
>>> func()
x is:100
Changed local x to:10
>>> print('Value of x:{}'.format(x))
Value of x:10
======================================================
这个函数内部多了一个global关键字,结果就差很多:
2.1.原因在于x被声明为函数内的全局变量,通过global这个语句是自己明确地映射到了模块的作用域
2.2.函数内对x重新赋值x=10,会改变函数外x的值,所以最后print x是10
全局变量简单说就是这3点:
@全局变量是位于模块文件内部的顶层的变量名
@全局变量如何是在函数内被改变的话,一定要用global
@全局变量名在函数内部不经过声明也可以被引用
3)函数内的变量解析原则
python的搜索顺序是:
@先是在函数内部的本地作用域(L)
@然后是在上一层的函数的本地作用域(E)
@然后是全局作用域(G)
@最后是内置作用域(B)
简单说就是从局部到中央,好比你找一个人,村里找不到找乡->乡里找不到找市里->市里找不到找到全国档案局
3.1.本地函数
在函数内部(def或者lambda)通过任何方式赋值的,而且没有在该函数内声明为全局变量的变量名
3.2.上层函数的本地作用域
python函数是支持嵌套,而且多层嵌套,当你在最里层的函数找不到这个变量的时候,会往上一层的函数找,一层一层由内往外找
======================================================
>>> def f1():
x = 100
def f2():
print(x)
f2()
>>> print(f1())
100
None
======================================================
#因为f2()打印了之后没有return,对没有return的函数就默认返回None
@def定义了一个f1()函数,里面又嵌套了一个f2()函数,这个def生成了一个函数并将其赋值给变量名f2
@f2是f1的本地作用域内的一个本地变量,可以把f2看做一个临时函数,仅仅在f1内部执行的过程中存在.
@f2函数干了一件事打印x,当在f2()内部找不到的时候,就通过LEGB法则往上找,f1()里面找到了x.
3.3.全局(模块)
在模块文件的顶层赋值的变量名,或者在该文件中的def生成的名为全局变量的变量名(函数内global声明的变量)
3.4.内置的作用域
2.函数参数传递
Python里面对函数参数传递分以下几种:
@位置参数
@默认参数 #在函数运行前参数就被赋了值
@关键字参数 #通过变量名字进行匹配,而不是通过位置
@可变长度参数
1)任意多个非关键字可变长参数(元组)
2)任意多个关键字变量参数(字典)
1)位置参数
python中最普通的函数使用是这种带位置参数的函数,这跟我们其他语言的普通的函数是一样的,所有参数在传递的时候按照位置来传递
======================================================
>>> def printMessage(message, times):
print(message * times)
>>> printMessage('Hi', 2)
HiHi
======================================================
2)默认参数
======================================================
>>> def printMessage(message, times=3):
print(message * times)
>>> printMessage('python')
pythonpythonpython
======================================================
3)关键字参数
在调用函数的时候,我们希望传递的参数不是僵硬的通过位置来传递,能够有一定的灵活性,能通过变量名进行匹配
======================================================
>>> def func(a, b=10, c=20):
print('a is: ', a, 'and b is: ', b, 'and c is: ', c)
>>> func(3,7) #没有关键字,就用默认的位置传递
a is: 3 and b is: 7 and c is: 20
>>> func(25, c=24) #可以跳过b直接到c的赋值
a is: 25 and b is: 10 and c is: 24
>>> func(c=50, a=100) #使用关键字赋值,无需注意顺序
a is: 100 and b is: 10 and c is: 50
======================================================
4)任意多个位置参数的函数
我们在参数values前面加*,变成(msg,*values),表示只有第一个参数的msg是调用者必须要指定的,该参数后面,可以跟任意数量的位置参数
======================================================
>>> def printScore(msg, *values):
if not values:
print(msg)
else:
values_str = ','.join(str(x) for x in values)
print('{},{}'.format(msg,values_str))
>>> print('My scores are')
My scores are
>>> print('My scores are', 100, 90, 80)
My scores are 100 90 80
======================================================
一下把100,90,80都打印出来呢,是怎么做到的,是因为python会自动把*操作符后面的形参变成元组传给函数.
5)任意多个关键字形式的参数
如何能接受任意数量的关键字参数,是用**双星号操作符来表示
======================================================
>>> def printLog(msg, **theRest):
if not theRest:
print(msg)
else:
for key,value in theRest.items():
print('{},{}={}'.format(msg,key,value))
>>> printLog('Log info', version='1.0', platfrom='win')
Log info,version=1.0
Log info,platfrom=win
======================================================
其实就是把**后面的变量参数,按照字典来处理,传递给函数.
综合例子:
包含了关键字参数,默认参数,可变任意数量参数
======================================================
def total(initial=5, *numbers, **keywords):
count = initial
for number in numbers:
count += number
for key in keywords:
count += keywords.get(key)
return count
======================================================
>>> total(10, 1, 2, 3, apple=50, orange=100)
166