python 函数及模块
为什么要自定义函数
避免重复代码的频繁出现
定义函数
例如:
y=2x y相当于return返回的值,x相当于参数,2相当于自定义函数
Python中使用def关键字来定义函数,命名规则跟变量的命名规则是一致的。在函数名后面的圆括号中可以放置传递给函数的参数,这一点和数学上的函数非常相似,程序中函数的参数就相当于是数学上说的函数的自变量,而函数执行完成后通过return关键字来返回一个值,这相当于数学上说的函数的因变量。
def double(a=0,b=0):
return b*a
a=1
b=2
d = double(a,b)
print d
print(double(1,2))
print(double(b=2,a=1)) #可以不按指定的顺序传
在不确定参数个数的时候,我们还可以使用可变参数,代码如下所示。
# 在参数名前面的*表示args是一个可变参数
# 即在调用add函数时可以传入0个或多个参数
def add(*args):
total = 0
for val in args:
total += val
return total
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
用模块管理函数
在同一个.py文件中定义了两个同名函数,由于Python没有函数重载的概念,那么后面的定义会覆盖之前的定义,两个同名函数实际上只有一个生效
def demo():
print('hello')
def demo():
print('ok')
# 下面的代码会输出什么呢?
demo() #ok
怎么解决这种命名冲突呢?
其实Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过import关键字导入指定的模块就可以区分到底要使用的是哪个模块中的foo函数,代码如下所示。
module1.py
def demo():
print('hello')
module2.py
def demo():
print('ok')
test.py
from module1 import demo
demo() # hello
from module2 import demo
demo() # ok
也可以下面的方式来区分到底要使用哪一个函数。
test.py
import module1 as m1
import module2 as m2
m1.demo()
m2.demo()
但是如果将代码写成了下面的样子,那么程序中调用的是最后导入的那个foo,因为后导入的foo覆盖了之前导入的foo。
test.py
from module1 import demo
from module2 import demo
foo() # 输出ok
反之输出hello
因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是__main__
module3.py
def demo():
pass
def demo1():
pass
# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
print('call demo()')
print('call demo1()')
test.py
import module3
# 导入module3时 不会执行模块中if条件成立时的代码 因为模块的名字是module3而不是__main__
Python中有关变量作用域
def demo():
b = 'hello'
def bar(): # Python中可以在函数内部再定义函数
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索,前三者我们在上面的代码中已经看到了,所谓的“内置作用域”就是Python内置的那些隐含标识符min、len等都属于内置作用域)。
没有定义在任何一个函数中的变量,属于全局作用域。
在上面的demo函数中我们定义了变量b,在函数中的变量,属于局部作用域,在foo函数的外部并不能访问到它
demo函数内部的bar函数来说,变量b属于嵌套作用域,在bar函数中我们是可以访问到它的。
bar函数中的变量c属于局部作用域,在bar函数之外是无法访问的
再看看下面这段代码,我们希望通过函数调用修改全局变量a的值,但实际上下面的代码是做不到的。
def foo():
a = 200
print(a) # 200
if name == ‘main’:
a = 100
foo()
print(a) # 100
在调用foo函数后,我们发现a的值仍然是100,这是因为当我们在函数foo中写a = 200的时候,是重新定义了一个名字为a的局部变量,它跟全局作用域的a并不是同一个变量,因为局部作用域中有了自己的变量a,因此foo函数不再搜索全局作用域中的a。如果我们希望在foo函数中修改全局作用域中的a,代码如下所示。
def foo():
global a
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 200
使用global关键字来指示foo函数中的变量a来自于全局作用域,如果全局作用域中没有a,那么下面一行的代码就会定义变量a并将其置于全局作用域。同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用nonlocal关键字来指示变量来自于嵌套作用域,请大家自行试验。
在开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被垃圾回收。事实上,减少对全局变量的使用,也降低代码之间耦合度。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在函数调用结束后依然可以访问,这时候就需要使用闭包
def main():
# 自己的代码
pass
if name == ‘main’:
main()