1,初识函数
# 函数 s = '杭州海博' # 定义一个函数实现len(s)的功能 # 定义函数 def(): # def my_len(): # 函数名:字母,下划线,数字,不能以数字开头,避免关键字 # i = 0 # for k in s: # i += 1 # print(i) # # # 调用函数,必须带上() # my_len() # leng = my_len() # print(leng) # 结果为None,说明没有返回值 # # 函数的特点:定义了之后,可以在任何需要它的地方调用这个函数 # # 加一个函数的返回值 # def my_len(): # i = 0 # for k in s: # i += 1 # print(i) # return i # 加返回值 # my_len() # leng = my_len() # print(leng) # 结果为4,有返回值 # 返回值的三种情况 #1,没有返回值--返回None 1.1,函数里面没有写return .1.2,只写了”return“,return代表结束一个函数。1.3,写return None,这个最不常用的 #2,返回1个值:2.1,可以返回任何数据类型 2.2,只要返回了就可以直接接收 2.3,如果在一个程序里面有多个return,只执行第一次运行的代码 #3,返回多个值:3.1,有多少返回值就用多少变量接受。 3.2,多个返回值,用一个变量接受:得到的是一个元祖 # def func(): # return 1,2,3 # r = func() # print(r) # (1, 2, 3)
2,函数的参数
# 函数的参数 # def my_len(s): # 接受参数,形式参数 # i = 0 # for k in s: # 注意这个s要跟形参s一样 # i += 1 # return i # s = '杭州海博' # ret = my_len(s) # 调用函数的时候传递参数,实际参数 # ret = my_len([1,2,3]) # 调用函数的时候传递参数,实际参数 # print(ret) # 参数的几种情况 ''' 1,没有参数,定义函数时候括号里面不写内容 2,有一个参数 3,有多个参数 3.1 位置参数 3.2,关键字传递参数 3.3 不能给同一个变量传递多个变量 ''' # 站在实参的角度上: # def my_sum(a,b): # res = a + b # return res # ret = my_sum(1,2) #位置参数 # ret = my_sum(a = 1,b = 2) # 关键字传递参数 # ret = my_sum( 1, b=2) #混着使用可以,但必须先位置,再关键字 # print(ret) # 站在形参的角度上 #位置参数:必须传,有几个参数就传几个值 #*args:动态参数,可以接受任意多个按位置传入的参数 #默认参数,可以不传 #**kwargs,可以接受任意多个按关键字传入的参数 # 定义函数的时候: ''' 1,位置参数:直接定义参数 2,默认参数,关键字参数:参数名= ”默认值“ 3,动态参数:可以接受任意多个参数 参数名前加* 参数名习惯用args, *args:接收的是按照位置传参的值,组织成一个元祖 **kwargs:接收的是按照关键字传参的值,组织成一个字典 4,顺序:必须先定义位置参数,动态参数*args,定义默认参数,**kwargs ''' # def classmate(name,sex='男'): # print('%s:%s'%(name,sex)) # classmate('张三') # classmate('小美','女') #动态参数,求多个值得和 # def sum(*args): # *args是一个元祖,args也可以改成别的名字 # sum = 0 # for i in args: # sum = sum + i # return sum # sum = sum(1,2,3,4) # print(sum) # def func(**kwargs): # **代表字典,形参名习惯用kwargs # print(kwargs) # func(a=1,b=2,c=3) # func(a=1,b=2) # func(a=1) # 动态参数的另一种传参方式 # def func(*args): # 站在形参的角度上,给变量加上*,就是组合所有传来的值 # print(args) # func(1,2,3,4,5) # li = [6,7,8,9] # func(*li) # (6, 7, 8, 9) 站在实参的角度上,给一个序列加上*,就是将这个序列按照顺序打散 # def func(**kwargs): # 站在形参的角度上,给变量加上*,就是组合所有传来的值 # print(kwargs) # func(a=1,b=2) # li = {'a':1,'b':2} # func(**li) # 站在实参的角度上,给一个字典加上*,就是将这个字典按照顺序打散 # 函数的注释 # def func(): # ''' # 这个函数实现了什么功能 # 参数1:什么,, # 参数2:什么,,, # # :return: 是什么东西 # ''' # pass # 关于默认参数的陷阱: # def qqxing(li = []): # li.append(1) # print(li) # qqxing() #[1] # qqxing([]) #[1] # 传了参数,所有列表只有一个1 # qqxing() # [1, 1] 如果默认参数的值是一个可变数据类型,那么每一次调用这个函数的时候不传值就公用这个数据类型的资源 # qqxing() # [1, 1, 1]
3,函数的嵌套和作用域
# 函数的嵌套定义 # 嵌套中,内部函数可以使用外部函数的变量 # a = 1 # def outer(): # a = 1 # def inner(): # b = 2 # print('第二层:',a) # print('inner') # def inner2(): # nonlocal a # 如果第二层没有a,就继续上一层,对全局无效的 # a += 1 # print(a,b) # print('inner2') # inner2() # # inner() # print('第一层:',a) # outer() # print('全局:',a ) #nonlocal只能用于局部变量,找上层中离当前函数 最近 一层 的局部变量。只会影响一层。 def func(): print(123) func2 = func # 函数名可以赋值,函数名本质就是在内存中的储存地址 func2() li = [func,func2] #函数名可以作为容器类型的元素 for i in li: i() def wahaha(f): # 函数名可以作为函数的参数 f() return f # 函数名可以作为函数的返回值 qqxing = wahaha(func) qqxing() print(wahaha(func))
4,命名空间和作用域
#函数进阶--命名空间 #全局命名空间:--我们写的代码和函数名 ''' 是程序从上到下被执行的过程中依次被加载进内存的 放置了我们所设置的变量名和函数名 ''' #局部命名空间--函数 ''' 就是函数内部定义的名字 当调用函数的时候才会产生这个命名空间,函数结束,命名空间消失 ''' #内置命名空间:--python解释器 ''' 就是python解释器一启动就可以直接使用的名字存储在内置命名空间中,内置的名字在启动解释器的时候被加载进内存里 比如:print(),input(),list ,tuple ''' ''' 在局部:可以使用全局、内部 在全局:可以使用内部,不能使用局部 在内部:不能使用局部和全局 ''' # print(max(1,2)) # 2 # def max(): # print('in max func') # max() # # 结果: # # in max func # print(max()) # #结果: # #in max func # #None #在正常情况下,直接使用内置的名字 #当我们在全局定义了何内置空间中名字同名的名字时,会使用全局的名字 #当我自己有的时候,就不要找我的上级要了 #如果自己没有,就找上一级要,如果找内置空间的名字都没找到就报错 # def func(): # pass # print(func) # #func--->对应的函数的内存地址 # #函数名(),加了()才是函数的调用 # #也等于函数的内存地址() #作用域:只有两种 ''' # 1,全局作用域 # 作用在全局,内置和全局名字空间中的名字都属于全部作用域 # 2,局部作用域 # 函数 # ''' # a = 1 # def func(): # global a # a += 1 # 如果上面没有global a,会报错 # print(a) # func() #对于不可变数据类型,在局部能查看全局作用域中的变量,但不能直接修改,如果需要修改,需要再函数的开始添加global声明 #如果再一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效 a = 1 b = 2 def func(): x = 'aaa' y = 'bbb' print(globals()) # 全局的变量名字 print(locals()) #{'y': 'bbb', 'x': 'aaa'} func() print(globals()) # 全局的变量 print(locals()) #还是全局的变量,因为locals翻译过来是本地的意思,跟代码位置有关系。 #globals 永远打印全局的名字 #locals 输出什么,跟位置有关系
5,闭包
#闭包:函数嵌套,内部函数调用外部函数的变量 # def outer(): # a = 1 # def inner(): # print(a) # print(inner.__closure__) # (<cell at 0x000001F6319D0B58: int object at 0x0000000064AC22D0>,) # outer() # print(outer.__closure__) #None # def outer(): # a = 1 # def inner(): # print(a) # return inner # 把函数名inner作为outer函数的返回值 # b = outer() # b() # 可以通过外部直接调用嵌套里面的函数 import urllib # 模块 from urllib.request import urlopen def get_url(): url = 'http://www.baidu.com/index.heml' def inner(): ret = urlopen(url).read() print(ret) return inner get = get_url() get()
6,函数的作业
# 函数的作业 # 写函数,接受n个参数,求这些参数的数字和 # def sum_func(*args): # total = 0 # for i in args: # total = total + i # return total # print(sum_func(12,3,4)) # 读代码,回答:代码中,打印出来的值,a,b,c分别是什么 # a = 10 # 顺序1 # b = 20 # 顺序2 # def test1(a,b): # 顺序3:定义函数 # print(a,b) # 顺序5,执行函数,打印出来20,10 # c = test1(b,a) # 顺序4:调用函数test1(b,a)就是test1(20,10) #顺序6,把函数test1的结果赋值为c,但是函数没有返回值,所以c为None # print(c) # 结果:# 这道题考的知识1,实参的变量名跟形参的变量名没有关系,2,函数返回值 3,关于赋值的c,要先把函数运行完,再赋值 # 20 10 # None # 读代码,回答:代码中,打印出来的值,a,b,c分别是什么 # a = 10 # b = 20 # def test2(a,b): # a = 3 # b = 5 # print(a,b) # c = test2(b,a) # print(c) # #结果 # #3,5 # #None # 写函数,检查获取传入列表或元祖对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者 # def func(l): # return l[1::2] # print(func([1,2,3,4,5])) # 这个题考的切片 #写函数,判断用户传入的对象(字符串,列表,元祖)长度是否大于5 # def func(l): # return len(l) > 5 # 大于或者小于是一个比较,返回bool值 # print(func((1,2,3,4))) # 写函数,检车传入列表的长度,如果大于2,仅保留前两个长度的内容,并将新内容返回给调用者 # def func(l): # if len(l)>2: # return l[0:2] #也可以不要if,如果小于的,返回就是本来的列表 # print(func([1,2,3,4])) # 写函数,计算传入字符串中【数字】,【字母】,【空格】以及【其他】的这四分类个数,并返回结果 # def func(s): # num = 0 # alpha = 0 # space = 0 # other = 0 # for i in s: # if i.isdigit(): # num += 1 # elif i.isalpha(): # alpha += 1 # elif i.isspace(): # space += 1 # else: # other += 1 # return ('数字数量:{} 字母数量:{} 空格数量:{} 其他数量:{} '.format(num,alpha,space,other)) # print(func('1a %')) # 上题方法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('1a %')) #写函数,检查用户传入的对象(字符串,列表,元祖)的每一个元素是否含有空内容,并返回结果 #'dfdg jkjl' 这个字符串算有一个空内容的,有个空格 #[1,2,3,'',[],(),'dfsaf jlkl'] 列表中字符串作为元素,不算空内容的 # def func(x): # if type(x) is str and x: # for i in x: # if i == ' ': # return True # elif type(x) is list or type(x) is tuple and x: # for i in x: # if not i: # return True # print(func([])) #写函数,检查传入字典的每一个value的长度,如果大于2,仅保留前两个长度的内容,并将新内容返回给调用者 #dic = {'k1':'vava','k2':[1,2,3,4]} value中只有字符串和列表 # def func(dic): # for k in dic: # if len(dic[k])>2: # dic[k] = dic[k][0:2] # return dic # dic = {'k1':'vava','k2':[1,2,3,4]} # 写函数,接受两个数字参数,返回大的数字 # def func(a,b): # if a>b: # return a # else: # return b # 两个数字一样的,就返回一个值 # print(func(3,3)) #上题方法2,三元运算 #变量 = 条件返回True的结果 if 条件 else 条件返回False的结果 #三元运算的调节: #必须要有结果,必须有if和else,必须是简单的运算 # def func(a,b): # c = a if a>b else b # return c # print(func(1,2)) #写函数,用户传入修改的文件名和要修改的内容,执行函数,批量操作 # def func(filename,old,new): # with open(filename,'r',encoding='utf-8') as f, open('%s.bak'%filename,'w',encoding='utf-8') as f2: # for line in f: # if old in line: # line = line.replace(old,new) # f2.write(line) # 可以多次write,不会被清空,只有在打开的一瞬间清空的。 # f2.write(line) # filename = '开会主题' # old = '电' # new = '气' # func(filename,old,new)
7,装饰器
import time # time.time() # 获取当前时间 # time.sleep(3) # 让程序在执行这个位置的时候停一会儿 # print('hahaha') # def func(): #顺序1 # time.sleep(0.02) # 顺序10 # print('大家好') #顺序11 # def timer(f): # 顺序2 #装饰器函数 # def inner(): #顺序4:执行timer函数,定义inner函数 # start = time.time() # 顺序8 # f() # 顺序9,f就是传入的实参func # 被包装的函数,不想被修改的 # end = time.time() # 顺序12 # print(end-start) # 顺序13 # return inner #顺序5:把inner作为返回值返回给timer函数 # func = timer(func) #顺序3:执行timer函数,把func值传入 顺序6,赋值func = inner # func() # 顺序7,func()就是inner(),执行inner函数 #装饰器的作用:不想修改函数的调用方式,但是还想在原来的函数前后添加功能 #timeer就是一个装饰器函数,只是对一个函数有一些装饰作用 ''' 原则:开放封闭原则 开放:对扩展是开放的 封闭:对修改是封闭的 封板: ''' #语法糖 # def timer(f): # def inner(): # start = time.time() # ret = f() # end = time.time() # print(end-start) # return ret # return inner # @timer # 语法糖 @装饰器函数名,相当于下面的func = timer(func) # def func(): # time.sleep(0.02) # print('大家好') # return '新年好' # # func = timer(func) # ret = func() # print(ret) #装饰带参数的函数的装饰器 # def timer(f): # def inner(*args,**kwargs): # start = time.time() # ret = f(*args,**kwargs) # end = time.time() # print(end-start) # return ret # return inner # @timer # 语法糖 @装饰器函数名,相当于下面的func = timer(func) # def func(a): # time.sleep(0.02) # print('大家好',a) # return '新年好' # # func = timer(func) # ret = func(1) # print(ret) # def wrapper(f): #装饰器函数,f是被装饰的函数 # def inner(*args,**kwargs): # '''在被装饰函数之前要做的事''' # ret = f(*args,**kwargs) # 真正被装饰的函数执行 # '''在被装饰函数之后要做的事''' # return ret # return inner # @wrapper # 语法糖 @装饰器函数名,相当于下面的func = timer(func) # def func(a): # time.sleep(0.02) # print('大家好',a) # return '新年好' # # func = timer(func) # ret = func(1) # print(ret) # def wapper(func): # def inner(*args,**kwargs): # print('在被装饰的函数之前做的事') # ret = func(*args,**kwargs) # print('在被装饰的函数之后做的事') # return ret # return inner # # @wapper #holiday = wapper(holidy) # def holiday(day): # print('全体放假%s天'%day) # return '好开心' # print(holiday(3)) #动态参数 # def outer(*args,**kwargs): #聚合 ,接收的时候组合成元祖 # print(args) #(1, 2, 3, 4) # print(*args) # 1 2 3 4 # 打散 ,调用的时候就打散啦 # def inner(*args): #聚合 # print(args) # print(*args) # 打散 # inner(*args) # outer(1,2,3,4) #等价于outer(*(1,2,3,4)),也等于outer(*[1,2,3,4])