Python开发-函数使用
1.1、命名空间
Python中一般有三种命名空间:
内置名称:Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
全局名称:模块中定义的名称,记录了模块的变量、函数、类、其它导入的模块、模块级的变量和常量。
局部名称:函数中定义的名称,记录了函数的变量、参数和局部定义的变量。
- 一个变量查找的顺序为:
局部的命名空间 -> 全局命名空间 -> 内置命名空间;
1.2、作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。
Python 的作用域一共有4种分别是:
L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
规则顺序: L –> E –> G –> B。
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
1.3、变量访问
1.3.1、全局和局部变量
#/usr/bin/python3
# coding=utf-8
from sys import path
ora_total=10
def chValue(newVaule):
ora_total=newVaule
return ora_total
print("the vaule of variable ora_total is {0} after changed:".format(chValue(30)))
print("then current value of variable ora_total is {0}:".format(ora_total))
#输出结果
the vaule of variable ora_total is 30 after changed
then current value of variable ora_total is 10
说明:在如上的代码中发现函数访问的ora_total 变量为函数内部的局部变量,没有改变模块中定义的全局变量;
变量申明
在Java和 c语言等,局部变量不能在外部使用;但是在Python中好像没有这个限制;
- 局部申明
def varArea():
try:
list_a=[333,444,555]
pass
except Exception as e:
print(e)
print(list_a)
varArea()
输出结果:
[333, 444, 555]
Process finished with exit code 0
- 提前申明
def varArea():
list_a=None
print(list_a)
try:
list_a=[333,444,555]
pass
except Exception as e:
print(e)
print(list_a)
varArea()
输出结果:
None
[333, 444, 555]
Process finished with exit code 0
1.3.2、global和nonlocal
- 修改全局变量
当内部作用域想修改外部作用域的变量时,需要用到 global 和 nonlocal 关键字;
#/usr/bin/python3
# coding=utf-8
from sys import path
ora_total=10
def chValue(newVaule):
global ora_total
ora_total=newVaule
return ora_total
print("the vaule of variable ora_total is {0} after changed".format(chValue(30)))
print("then current value of variable ora_total is {0}".format(ora_total))
#结果输出
the vaule of variable ora_total is 30 after changed
then current value of variable ora_total is 30
说明: 如上代码中函数内部申明访问的为全局变量,在赋值时需要另起一行,不能直接和申明全局变量放到同一行;
- 修改嵌套作用域
如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字
#/usr/bin/python3
# coding=utf-8
from sys import path
def outerChValue(newVaule):
lol_num=100
print("the original value of local variable is {}".format(lol_num))
def innerChValue(newValue):
nonlocal lol_num
lol_num=newVaule
innerChValue(newVaule)
print("the value of local variable is {} after changed".format(lol_num))
outerChValue(77)
#结果输出
the original value of local variable is 100
the value of local variable is 77 after changed
1.4、函数
1.4.0、语法格式
def funName(var_1,var_2,...var_n):
# do something
pass
return $relult
参数传递分为值传递和引用传递;
-
值传递
值传递的参数对象为不可变对象,主要为字符串、数值、元组,传入的是对象的值,传入后原始对象和参数脱离关系; -
引用传递
传入的是对象的引用,主要为列表、集合、字典等,在函数内部更改对象的值,外部对象值会同步改变;
说明:默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
可更改(mutable)与不可更改(immutable)对象
-
在 python 中,strings、tuples、numbers 是不可更改的对象,而 list、dict、set 等则是可以修改的对象。
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个类型为int值为10的对象,再让 a 指向它,而 5 被丢弃,不是改变 a 的值;
-
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
1.4.1、参数传递
python 函数的参数传递:
- 不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
>>>
>>> def change_para(a):
... a+=5
... return a
...
>>> int_a=10
>>> change_para(int_a)
15
>>> print(int_a)
10
>>>
- 可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
>>>
>>> def change_list(param):
... del param[0]
... return param
...
>>> list_h=["aaa","bbb","ccc","ddd","eee"]
>>> change_list(list_h)
['bbb', 'ccc', 'ddd', 'eee']
>>> print(list_h)
['bbb', 'ccc', 'ddd', 'eee']
>>>
- python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
1)关键字参数和默认值参数
>>> def infor_pet(name,place,age=3):
... print("Age of your pet is %d,name of your pet is %s,place of your pet comes from %s "%(age,name,place))
...
>>> infor_pet(place="market",name="Qzai")
Age of your pet is 3,name of your pet is Qzai,place of your pet comes from market
>>>
说明:默认参数必须写在最后,对于无需返回值的函数,可以没有 return 语句;
2)不定长变量
- 第一种:加 * 的元组参数
def cal_sum( arg1, *vartuple ):
sum=arg1
for x in vartuple:
sum+=x
return sum
cal_sum(10,20,30,40)
- 第二种:加 ** 的字典参数
def cal_sum( arg1, **varDict ):
sum=arg1
for x in varDict.values():
sum+=x
return sum
cal_sum(10,a=20,b=30,c=40)
3)关键字参数
Python中声明函数时,参数中星号 * 可以单独出现,此时 * 后的参数必须用关键字传入。
def calVolume(length,width,*,heigth):
volume=length*width*heigth
return volume
# 错误调用方式
vol_1=(10,20,30)
# 正确调用方式
vol_2=(10,20,heigth=30)
1.4.2、lambda函数
Python 使用 lambda 来创建匿名函数,即不再使用 def 语句这样标准的形式定义的函数。
特点:
1)lambda 只是一个表达式,函数体比 def 简单很多;
2)lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
3)lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
语法规则:
lambda [arg1 [,arg2,.....argn]]:expression
示例代码:
>>>
>>> fun_a=lambda a,b:a*b
>>> print(fun_a(4,5))
20
1.4.4、类型转换
-
int(x [,base])
-
float(x)
-
complex(real [,imag])
-
str(x)
-
repr(x)
-
eval(str)
-
tuple(s)
-
list(s)
-
set(s)
-
dict(d)
-
frozenset(s)
功能:转换为不可变集合 -
chr(x)
功能:将一个整数转换为一个字符 -
ord(x)
功能:将一个字符转换为它的整数值 -
hex(x)
功能:将一个整数转换为一个十六进制字符串 -
oct(x)
功能:将一个整数转换为一个八进制字符串
1.4.5、随机函数
随机函数需要导入模块 random
import random
random.choice(seq)
random.randrange(start,stop,step)
random.random()
shuffle(lst)
1.4.6、返回值
Python的函数可以有多个返回值,实际通过 type 可以发现返回的是一个 tuple(元组) ;所以可以有多个参数接收 一个函数的多个返回值;
1.4.7、递归函数
def factorials(n:int):
if(n<=0):
sys.exit("请输入正整数参数")
elif(n==1):
return n
else:
return n * factorials(n-1)
- 递归优化
递归函数对递归的层级有限制,当超出 栈的最大深度时将会抛出异常:
def levelSum(n:int):
if(n<=0):
sys.exit("请输入正整数参数")
elif(n==1):
return n
else:
return n + levelSum(n-1)
print(levelSum(1000))
输出结果:
D:\SoftWare\Python\python.exe E:/PythonProject/FileOperTest/funDemo01.py
Traceback (most recent call last):
File "E:\PythonProject\FileOperTest\funDemo01.py", line 28, in <module>
print(levelSum(1000))
File "E:\PythonProject\FileOperTest\funDemo01.py", line 27, in levelSum
return n + levelSum(n-1)
File "E:\PythonProject\FileOperTest\funDemo01.py", line 27, in levelSum
return n + levelSum(n-1)
File "E:\PythonProject\FileOperTest\funDemo01.py", line 27, in levelSum
return n + levelSum(n-1)
[Previous line repeated 995 more times]
File "E:\PythonProject\FileOperTest\funDemo01.py", line 22, in levelSum
if(n<=0):
RecursionError: maximum recursion depth exceeded in comparison
Process finished with exit code 1
1.4.8、名称获取
某些场景下,在函数内部需要获取或输出函数自己的名称信息,此时可以通过 sys._getframe().f_code.co_name
获取;
import sys
def recordTest():
print("current step is in function {}!".format(sys._getframe().f_code.co_name))
if __name__ == "__main__":
print("the module app is running!")
recordTest()
控制台输出:
the module app is running!
current step is in function recordTest!
Process finished with exit code 0
1.5、模块
1.5.1、模块导入
模块导入方式如下三种:
from module import fun1,fun2,fun3
from module import *
import module
__name__属性
一个模块被其他程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。
#!/usr/bin/python3
def DisplayCore():
if __name__=="__main__":
print("My main function body is running!")
else:
pass
return
说明: 每个模块都有一个__name__属性,当其值是"__main__"时,表明该模块自身在运行,否则是被引入。
说明:__name__ 与 __main__ 底下是双下划线, _ _ 是这样去掉中间的那个空格。
1.5.2、包导入
- 方式一:
from pkg_par.pkg_son.module import fun1
说明:这种导入方式 函数 fun1 可以直接使用;
- 方式二:
from pkg_par.pkg_son import module.fun1
说明:这种导入方式 函数 fun1 需要按照 module.fun1 的方式使用;
- 方式三:
import pkg_par.pkg_son.module.fun1
说明:这种导入方式 函数 fun1 需要按照全路径使用:pkg_par.pkg_son.module.fun1;
强调:模块相对路径导入只能使用
from xx.xx.xx import xx
的方式;不能直接使用import ..xx.xx.xx
的方式;
1.6、偏函数
Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。
简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
如:max2 = functools.partial(max, 10)
等同于
args = (10, 5, 6, 7)
max(*args)
================================ over ========================================
上一篇:Python—2、对象操作
下一篇:Python—8、面向对象