Python菜鸟编程第六课之函数
1.引子
函数是对程序逻辑进行结构化或者过程化的一种编程方法
demo:
#给出两个数,求第一个数到第二个数之间的总和
def sumc(num1, num2):
sum = 0
while num1 <= num2:
sum = sum + num1
num1 += 1
return sum
print(sumc(1, 4))
print(sumc(1, 15))
print(sumc(23, 36))
print(sumc(55, 68))
运行结果:
10
120
413
861
2.函数的使用
语法:
def function_name(arg1,arg2,..):
'''statements'''#这里一般存放函数解释
function_statements
return value
2.1函数文档说明
使用function.__doc__来查看函数的说明文档
demo:
def add(x,y):
'''求和'''
return x+y
print(add.__doc__)
运行结果:
求和
2.2函数参数
函数中,参数的定义顺序必须是位置参数、默认参数、可变参数、命名关键词参数和关键词参数
函数参数种类:
- 形参:只有在调用时才分配内存单元,调用结束后释放所分配的内存单元,因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
- 实参:实参是一个确定的值,能够传输给形参。
def info(name,age):
info={"name" :name,"age":age}
return info
print(info('city',1823))
print(info('小刘',18))
运行结果:
{'name': 'city', 'age': 1823}
{'name': '小刘', 'age': 18}
demo2:
print('1'.center(10, '*'))
test(1, 2)
print('2'.center(10, '*'))
test(x=1, y=2)
print('3'.center(10, '*'))
test(y=2, x=1)
print('4'.center(10, '*'))
test(1, y=2)
print('1'.center(10, '*'))
test(y=2, 1)#参数位置错误,结果报错
运行结果:
****1*****
1
2
****2*****
1
2
****3*****
1
2
****4*****
1
2
****1*****
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 95
test(y=2, 1)
^
SyntaxError: positional argument follows keyword argument
2.21位置参数
demo:
#位置参数
def user_manage(name, age, job, hobby):
print('用户管理系统'.center(16, '-'))
print('\t:Name\t', name)
print('\t:Age\t', age)
print('\t:Job\t', job)
print('\t:Hobby\t', hobby)
user_manage('Tom', 20, 'IT', 'Eat')
运行结果:
-----用户管理系统-----
:Name Tom
:Age 20
:Job IT
:Hobby Eat
2.22默认值参数
函数中给予了参数默认值,假如调用函数时传参,会使用传递的参数,假如不传参,则使用默认值参数。
demo:
#默认值参数
def user_manage(name, age, job, hobby='Trip'):
print('用户管理系统'.center(16, '-'))
print('\t:Name\t', name)
print('\t:Age\t', age)
print('\t:Job\t', job)
print('\t:Hobby\t', hobby)
user_manage('Tom', 20, 'IT', 'Eat')
user_manage('Tom', 20, 'IT', )
运行结果:
-----用户管理系统-----
:Name Tom
:Age 20
:Job IT
:Hobby Eat
-----用户管理系统-----
:Name Tom
:Age 20
:Job IT
:Hobby Trip
2.3关键词参数:
用于函数调用,通过“键-值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。
默认值参数,关键词参数,必须放在位置参数之后
demo:
def print_hello(name, sex):
sex_dict = {1: u'先生', 2: u'女士'}
print ('hello %s %s, welcome to python world!' %(name, sex_dict.get(sex, u'先生')))
# 以下是用关键字参数正确调用函数的实例
print_hello('tanggu', sex=1)
print_hello(name='tanggu', sex=1)
print_hello(sex=1, name='tanggu')
# 以下是错误的调用方式
print_hello(1, name='tanggu')#print_hello()为参数“name”获取多个值.
print_hello(name='tanggu',1)#参数位置放错
print_hello(sex=1, 'tanggu')#参数位置放错
2.4不定参数
在python中,不定参数主要是指*args和**kwargs。
它两主要用于函数定义,
*args 用来接收任意非键值对的任意数量的参数列表给函数,返回元组类型。
**kwargs 用来接收任意不定长的键值对列表给函数,返回字典类型。
demo1:
def uncertain_para(para, *args):
print('普通位置参数:', para)
print('不定参数:', args)
print(type(args))
uncertain_para(1,2,3,4,'a','b')
uncertain_para([1,2,3],'ab','dc')
普通位置参数: 1
不定参数: (2, 3, 4, 'a', 'b')
<class 'tuple'>
普通位置参数: [1, 2, 3]
不定参数: ('ab', 'dc')
<class 'tuple'>运行结果:
demo2:
def avg(*a):
sum = 0
for i in a:
sum += i
return sum / len(a)
print(avg(5, 5, 5))
print(avg(3, 4, 5))
运行结果:
5.0
4.0
demo3:
def un_para_key(**kwargs):
print(kwargs)
print(type(kwargs))
un_para_key(a=1,b=2,c=3)
运行结果:
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>
demo4:
def un_para_key(aa,bb,*cc,**kwargs):
print(aa)
print(bb)
print(cc)
print(kwargs)
print(type(kwargs))
un_para_key(1,2,3,4,5,6,'a','b',a=1,b=2,c=3)
运行结果:
1
2
(3, 4, 5, 6, 'a', 'b')
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>
练习题
写一个函数,计算传输字符中的数字,字母,空格以及其他字符的个数。
def strcount(str):
nsum = 0
asum = 0
ksum = 0
osum = 0
for i in str:
if i.isdigit():
nsum += 1
elif i.isalpha():
asum += 1
elif i == ' ':
ksum += 1
else:
osum += 1
print('字符串中数字的数量为:',nsum)
print('字符串中字母的数量为:', asum)
print('字符串中空格的数量为:', ksum)
print('字符串中其他字符的数量为:', osum)
strcount(str1)
运行结果:
请输入一串字符串qqww,,, 123456
字符串中数字的数量为: 6
字符串中字母的数量为: 4
字符串中空格的数量为: 3
字符串中其他字符的数量为: 3
2.3函数属性
demo1:
def bar():
print('in bar')
def foo():
print('in foo')
bar()
foo()
运行结果:
in foo
in bar
demo2:
新建一个py文件,名字命名为daylistudy.py.通过cmd运行此文件。
#daylistudy.py
def foo():
'''foo()---properly creat string'''
def bar():
pass
bar.__doc__='Oops,forget the doc str above'
bar.version=1.0
#控制台输入:
D:\PyCharm\BClass\PXClass\2019-7-23>python -i daylistudy.py
>>> dir()
['__annotations__', '__builtins__', '__cached__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'bar', 'foo']
>>> help(foo)
Help on function foo in module __main__:
foo()
foo()---properly creat string
>>> bar.__doc__
'Oops,forget the doc str above'
>>> bar.version
1.0
>>>
2.4内嵌函数
demo:
def foo():
def bar():
print("bar() called.")
print("foo() called.")
bar()
foo()
#调用bar()
bar()
运行结果:
foo() called.
bar() called.
#调用bar()。bar()整个函数都处于外部foo()函数的作用域里(fool()是我们可以从外部访问的一个对象区域)。除了在fool()内部,其他地方无法对bar()进行调用。
Traceback (most recent call last):
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 210, in <module>
bar()
NameError: name 'bar' is not defined
2.5变量作用域
作用域的产生:就作用域而言,python 和C语言有很大的差别,只有当变量在module,class,函数中定义的时候,才会有作用域 的概念。
demo:
def foo():
a='foo'
print(a)
foo()
print(a)
运行结果:
foo
Traceback (most recent call last):
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 216, in <module>
print(a)
NameError: name 'a' is not defined
在作用域中定义的变量,一般只在作用域内有效。需要注意的是,在if–elif–else,for–else,while–else,try–except(else–finally)等关键词的语句块中不会产生作用域。
demo:
if True:
a=100
print(a)
运行结果:
100
作用域的类型:Python中,使用一个变量时并不需要预先声明。但在真正使用的时候,他必须绑定在某个内存对象(被定义,赋值)。这种变量的绑定将在当前作用域中引入新的变量,同时,屏蔽外层作用域中的同名变量。
-
局部作用域(locale—L)
局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
注意:如果需要在函数内部对全局变量赋值,需要在函数内部通过global语句声明该变量为全局变量。 -
嵌套作用域(enclosing—E)
E也包含在def关键字中,E和L是相对的,E相对于跟上层的函数而言也是L.与L的区别就在于:对于一个函数而言,L是定义在定义此函数内部的局部作用域。主要为了实现Python的闭包,而增加的实现。
-
全局作用域(Global—G)
即在模块层次中定义的变量。模块顶层申明的变量具有全局作用域,从外部来看,模块的全局变量就是一个模块对象的属性。
-
内置作用域(built—B)
系统固定模块中定义的变量。
搜索变量名的优先级:
局部作用域>嵌套作用域>全局作用域>内置作用域
2.6全局变量和局部变量
demo:
gbl_str = 100#全局变量
def foo():
loc_str = 200#局部变量
return gbl_str + loc_str
print(foo())
print(gbl_str)
print(loc_str)
运行结果:
300
100
Traceback (most recent call last):
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 230, in <module>
print(loc_str)
NameError: name 'loc_str' is not defined
demo1:
a=6688
def foo():
a=666
print('foo(),修改前:\t',a)
a = 688
print('foo(),修改后:\t', a)
foo()
运行结果:
foo(),修改前: 666
foo(),修改后: 688
demo2:
a=6688
def foo():
# a=666
print('foo(),修改前:\t',a)
a = 688
print('foo(),修改后:\t', a)
foo()
运行结果:
Traceback (most recent call last):
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 237, in <module>
foo()
File "D:/PyCharm/BClass/PXClass/2019-7-23/daylistudy.py", line 234, in foo
print('foo(),修改前:\t',a)
UnboundLocalError: local variable 'a' referenced before assignment
demo1与demo2的运行差异,原因是在demo2中,foo()函数里搜索变量的优先级是局部作用域>全局作用域,当局部变量a与全局变量a重名,又由于优先级的存在,所以会报错。
demo3:
#将demo2中的变量a的变量名改为b
a=6688
def foo():
# a=666
print('foo(),修改前:\t',a)
b = 688
print('foo(),修改后:\t', a)
foo()
运行结果:
foo(),修改前: 6688
foo(),修改后: 6688