一: 函数的定义与调用
1.1 :函数的定义
- def 关键字必需写
- 函数名必需是字母,数字,下划线组合,并且不能以数字开头
- 函数名后面要加括号然后“:”
- 为函数写注释是一个好习惯
# 函数的定义 def 函数名(): 函数体
1.2: 函数的调用
- 使用函数名加括号进行函数的调用
- 函数名就时变量名,值为内存地址,加小括号就可以调用函数
# 函数的调用 函数名()
1.3:示例
# 示例 s = 'sdfsd'
# 函数的定义 def my_len():
def my_len(): i = 0 for k in s: i+=1 return i
# 函数的调用 my_len() length = my_len() print(length)
二:函数的返回值
函数的返回值很重要
return 关键字 如果想得到函数返回值 1:函数有返回的动作即函数有返回值 2:通过变量赋值的方式获取这个返回值 变量 = 函数调用
return 会将函数终止
2.1 没有返回值
默认是 None
1:不写return ------比较常用-比如我们只关注这个函数的功能,不关系他的返回值
def func(): l = ['wangys','xiaogongzhu'] for i in l: print(i) print(func())
2: 只写return ------- 比较常用-比如说只要满足某个条件就终止函数
def func(): l = ['wangys','xiaogongzhu'] for i in l: if i == 'wangys': print(i) return print(func())
3: return None ------不常用
2.2 返回一个值
1:可以返回任意数据类型
2:只要返回就可以接受到i
def func(): return 1 print(func()) def func(): return 'wangys' print(func()) def func(): return [1,2,3,4] print(func()) def func(): return {'name':'wangys'} print(func())
2.3 返回多个值
1:多个返回值用多个变量接收,有多少返回值,就用多少变量接收
2:也可以用一个变量接收,值是一个元祖(返回值组成)
def func(): return 1,2,3 r1,r2,r3=func() print(r1,r2,r3) def func(): return 1,2,3 r=func() print(r)
2.4 序列解压
# l 列表,通过与列表元素个数相当的变量接收 l=[1,2,3] a,b,c=l print(a,b,c) # 可以选择性的接收 l = [1,2,3,4,5] a,*_=l print(a) print(*_) 1 2 3 4 5 #
三: 函数的参数
参数分形参和实参之分
如下
def my_len(s): # s---形式的参数---形参 i = 0 for k in s: i+=1 return i print(my_len('sdfsd')) # sdfsd 实际的参数---实参
3.1 实参
传递参数时,分位置传参和按关键字传参。
位置在前,关键字在后
3.1.1 : 按照位置传参
def my_sum(a,b): res = a+b return res my_sum(1,2)
3.1.2 按照关键字传参
def my_sum(a,b): res = a+b return res print(my_sum(a=1,b=2)) print(my_sum(b=2,a=1))
3.1.3 :可以混用
但是位置实参必须在前,关键字实参必须在后,而且不能给参数传递多个值
# 位置参数在关键字参数的后面 SyntaxError: positional argument follows keyword argument def my_sum(a,b): res = a+b return res ret = my_sum(a=1,2) print(ret) # 给参数传递了多个值 TypeError: my_sum() got multiple values for argument 'a' def my_sum(a,b): res = a+b return res ret = my_sum(1,a=2) print(ret) # 正确的传参 关键字参数在后 位置参数在前 def my_sum(a,b): res = a+b return res ret = my_sum(1,b=2) print(ret)
3.2 形参
位置参数--*args---默认参数---**kwargs
位置参数:必须传
默认参数:可以不传参,如果不传,则使用默认值,如果传递了则使用传递的参数
函数的形参和实参并没有强的绑定关系,可以随意按照规则传递
3.2.1 位置形参
# 定义一个函数,函数有两个位置形参 def func(a,b): return a,b # 返回传递的参数 ret = func(1,2) # 按照位置传参,并获取函数的返回值 # 打印含绘制 print(ret)
def func(a,b): return a,b ret = func(a=1,b=2) # 按照关键字传参 print(ret)
3.2.2 动态参数*args
*args 可以传递多个参数 *参数名称 但习惯参数名称为args
不能接收关键字参数
按照位置参数传参的值
def my_sum(*args):
n = 0
for i in args:
n+=i
return n
print(my_sum(1,2))
print(my_sum(1,2,5,6))
def my_sum(*a):
n = 0
for i in a:
n+=i
return n
print(my_sum(1,2))
print(my_sum(1,2,5,6))
关键字参数传递报错
def func(*args):
pass
ret = func(1,2,3,a=b)
print(ret)
3.2.3 : 默认参数
默认参数可以不传递,如果不传递就使用默认值,如果传递就使用传递的参数
def classmate(name,sex='男'): res = ('%s:%s'%(name,sex)) return res ret = classmate('wangys') # sex是默认参数,没有传递参数 print(ret)
def classmate(name='wangys',sex='男'): res = '%s:%s'%(name,sex) return res ret = classmate('wangc','男') # name是默认参数,通过位置传递 print(ret)
3.2.4 动态参数**kwargs
按照关键字字参数的值,组织成一个字典,可以接收任意多个关键字参数
def func(**kwargs): print(kwargs) func(a = '1',b = '2')
3.2.5 *args **kwargs 组合使用,可以接收任意传参
def func(*args,**kwargs): print(args,kwargs) func(1,2,3,a = '4',b = '5')
3.2.6 给*args和**kwargs传参的另一种方式
def func(*args): # 将传递的参数聚合 print(args) l = [1,2,4,5] func(*l) # 将列表打散传递参数 def func(**kwargs): # 将传递的参数聚合 print(kwargs) d = {'a':1,'b':2} func(**d) # 将字典打散
3.3 可变数据类型做参数的陷阱
- 错误用法 每次调用修改的都是同一个列表
# 来自官方文档 def f(a, l=[]): l.append(a) return l print(f(1)) print(f(1)) print(f(1)) print(f(1)) [1] [1, 1] [1, 1, 1] [1, 1, 1, 1]
- 正确用法
def f(a, L=None): if L is None: L = [] L.append(a) return L print(f(1)) print(f(1)) print(f(1)) print(f(1)) [1] [1] [1] [1]
四 函数的注释
第一行应该是对象目的的简要概述。为简洁起见,它不应显式声明对象的名称或类型,因为这些可通过其他方式获得(除非名称恰好是描述函数操作的动词)。这一行应以大写字母开头,以句点结尾。
如果文档字符串中有更多行,则第二行应为空白,从而在视觉上将摘要与其余描述分开。后面几行应该是一个或多个段落,描述对象的调用约定,它的副作用等。
Python 解析器不会从 Python 中删除多行字符串文字的缩进,因此处理文档的工具必须在需要时删除缩进。 这是使用以下约定完成的。 文档字符串第一行 之后 的第一个非空行确定整个文档字符串的缩进量。(我们不能使用第一行,因为它通常与字符串的开头引号相邻,因此它的缩进在字符串文字中不明显。)然后从字符串的所有行的开头剥离与该缩进 “等效” 的空格。 缩进更少的行不应该出现,但是如果它们出现,则应该剥离它们的所有前导空格。 应在转化制表符为空格后测试空格的等效性(通常转化为8个空格)。
下面是一个多行文档字符串的例子:
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
def func(a,b): ''' 函数的主要功能 :param a: 参数a的含义 :param b: 参数的含义 :return: 返回值说明 ''' pass
五:命名空间及作用域
5.1 命名空间
5.1.1 内置命名空间
python解释器启动就可以使用的名字存储的命名空间
一旦python解释器启动,内置命名空间存储的名称就会放到内存中
在内置命名空间,不能使用全局和局部名称
5.1.2 全局命名空间
是在程序从上到下被执行的过程以此加载到内存中
可以使用内置的命名空间,但是不能使用局部的命名空间
5.1.3 局部命名空间
函数内部定义的名字
当函数被调用的时候,才会产生这个名称
可以使用全局的命名空间,也可以使用内置的命名空间
5.2 作用域
全局作用域----内置和全局名称空间内的名称 globals()
局部作用域--函数内部的 locals()
六 函数的嵌套
def max(a,b): return a if a>b else b def the_max(x,y,z): c = max(x,y) return max(c,z) print(the_max(1,2,3))
nonlocal 声明一个局部变量,该变量首先是局部变量,而且是里改函数最近的上一层函数内部局部变量 a=1 def outer(): a = 2 def inner1(): a = 3 def inner2(): nonlocal a a +=1 inner2() print('inner1局部变量a=3,现在是:', a) inner1() print("outer局部变量a=2,现在是:", a) outer() print('全局变量a=1现在是:',a)
七 函数的本质
函数名就是内存地址
def func(): print(123) print(func)
函数名可以赋值
def func(): print(123) func2 = func func2()
函数名可以作为容器类型的元素
def func(): print(123) func2 = func l = [func2,func] for i in l: i()
函数名可以作为函数的参数
def func(): print('133') def wangys(f): f() wangys(func)
函数名可以作为函数的返回值
def func(): print('123') def wangys(f): return f wangys(func)()
八:闭包函数
- 闭包函数:内部函数含有对外部作用域而非全局作用域名字的引用,那么该内部函数就称位闭包函数,通常我们会将闭包函数名进行返回,然后在外部进行调用
- 可以保护变量
- 变量常驻内存
def outer(): a =1 def inner(): print(a+1) return inner func = outer() func()
闭包函数的嵌套
def outer(): name='wangys' def func(): age=18 def inner(): print('My name is %s,i am %d year old'%(name,age)) return inner return func f = outer() # f=func print(f.__name__) i = f() # i=inner print(i.__name__) i()
from urllib.request import urlopen def index(): url='http://www.baidu.com' def inner(): return urlopen(url).read() return inner func = index() # func = inner ret = func() # 调用inner并且将返回值赋值给ret print(ret)
九:小练习题
计算 n个数字之和
def my_sum(*args): total =0 for i in args: total+=i return total print(my_sum(1,2,3))
写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
当去有规律去取一个列表或者元祖的元素的时候,可以使用切片
def func(l): return l[1::2] print(func([1,2,3,4,5]))
写函数,判断用户传入的值(字符串、列表、元组)长度是否大于5。
def func(x): return len(x)>5 print(func('wangys'))
写函数,检查传入列表的长度,如果大于2,
那么仅保留前两个长度的内容,并将新内容返回给调用者。
def func(x): return x[:2]
写函数,计算传入字符串中【数字】、【字母】、【空格】 以及 【其他】的个数,并返回结果。
def func(s): dic = {'num':0,'alpha':0,'space':0,'other':0} for i in s: if i.isdigit(): dic['num']+=1 elif i.isalpha(): dic['alpha']+=1 elif i.isspace(): dic['space']+=1 else: dic['other']+=1 return dic print(func('123sdfsd _+'))
写函数,检查传入字典的每一个value的长度,如果大于2,
那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
PS:字典中的value只能是字符串或列表
def func(dic): for i in dic: if len(dic[i])>2: dic[i]=dic[i][:2] return dic dic = {"k1": "v1v1", "k2": [11,22,33,44]} print(func(dic))
写函数,接收两个数字参数,返回比较大的那个数字。
#三元运算 # 变量= 条件为True的返回值 if 条件 else 条件为false的返回值 def func(a,b): c = a if a>b else b return c print(func(1,2)) def func(a,b): return a if a>b else b print(func(1,2))