Python函数
3.1 函数本质及应用场景
截止目前:面向过程编程(可读性差、可重用性差)
对于函数编程:
-
本质:将N行代码拿到别处并给他们起一个名字,方便以后通过名字就可以找到这段代码,并执行相关功能
-
应用场景:
- 代码重复执行
- 代码特别多,超过一屏,可以选择通过函数进行代码分割
-
面向过程编程:
# 面向过程编程 user_input = input('请输入角色:') if user_input == '管理员': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('管理员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["管理员", '344522251@qq.com']) msg['Subject'] = "亲爱的管理员" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['管理员', ], msg.as_string()) server.quit() elif user_input == '业务员': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('业务员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["业务员", '业务员']) msg['Subject'] = "亲爱的业务员" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['业务员', ], msg.as_string()) server.quit() elif user_input == '老板': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["老板", '老板邮箱']) msg['Subject'] = "亲爱的老板" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string()) server.quit()
-
函数是编程:
def send_email(): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["老板", '老板邮箱']) msg['Subject'] = "情爱的老板" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string()) server.quit() user_input = input('请输入角色:') if user_input == '管理员': send_email() elif user_input == '业务员': send_email() elif user_input == '老板': send_email()
3.2 函数定义(简单函数)
3.2.1 基本定义函数
-
基本形式
def 函数名(): #函数的定义 代码 #函数内容 函数名() #函数的执行
-
注意
- 函数如果不被调用,则内部代码永远不会被执行
- len(计算长度)是python内部写好的一个函数
3.2.2 参数(个数不限制)
3.2.2.1 基本参数知识
def get_list_date(aaa): #aaa:形式参数(形参) 任意个数
v = [11,22,33,44]
print(v[aaa])
get_list_date(1) #1:实际参数(实参) 任意类型
-
发送邮件问题
# 假如:管理员/业务员/老板用的是同一个邮箱。 def send_email(to): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('导演,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["导演", to]) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', [to, ], msg.as_string()) server.quit() def send_email(to): template = "要给%s发送邮件" %(to,) print(template) user_input = input('请输入角色:') if user_input == '管理员': send_email('xxxx@qq.com') elif user_input == '业务员': send_email('xxxxo@qq.com') elif user_input == '老板': send_email('xoxox@qq.com')
3.2.2.2 位置传参
-
传参:调用函数并传入参数
-
要求:严格按照位置进行传参
-
位置要求:positional argsument
-
基本形式:
def func(a,b): print(a,b) func(11,22) #位置都是一一对应的,a = 11,b = 22
3.2.2.3 关键字传参
- 关键字参数:keyword argsument
- 基本形式
def func(a,b):
print(a,b)
func(b = 11,a = 22) #按照关键字进行传参,可以交换位置
-
注意:open(打开文件)是python内部写好的一个函数,运用的就是关键字传参
-
关键字传参和位置传参可以混合使用
- 位置参数必须在关键字参数的前面
- 位置参数的个数 + 关键字参数个数 = 总参数个数
- 一个参数不能传入多次
3.2.2.4 默认参数:可传可不传
-
基本形式
def func(a,b = 9): #b就是默认参数,默认值为9 #func函数接受两个参数,调用函数进行传值时,默认参数可传可不传,不传则使用默认值,传则使用传的值 print(a,b) func(123) #a = 123,b使用默认值,即b = 9 func(11,22) #a = 11,b = 22
-
对于默认值,如果是可变类型(对于函数的默认值慎用可变类型)
# 如果要想给value设置默认是空列表 # 不推荐(坑) def func(data,value=[]): pass # 推荐 def func(data,value=None): if not value: value = []
-
面试题
def func(a,b=[]): b.append(a) return b l1 = func(1) l2 = func(2,[11,22]) l3 = func(3) print(l1,l2,l3) # [1,3] [11,22,2] [1,3]
3.2.2.5 万能参数(*args,**kwargs)
-
*args
-
可以接受人以个数的位置参数,并将参数转化为元组(注意实参里面有和没有*的区别)
-
只能使用位置传参
-
基本参数
def func(*args): print(args) func(1,2) #args = (1,2) func((11,22,33)) #args = ((11,22,33),) func(*(11,22,33)) #args = (11,22,33) 循环元组里的元素,加入到元组中 func(*[11,22,33,44]) #args = (11,22,33,44) 循环列表里的元素,加入到元组中 #注意实参里有*和没有的区别 #特殊情况: def func(a,*args,b): #a只能使用位置参数,b只能使用关键字参数 print(a,args,b) func(1,2,3,4,b = 5) #a = 1,args = (2,3,4),b = 5
-
-
**kwargs
-
可以接受任意个数的关键字参数,并将参数转化为字典(注意实参里面有**和没有的区别)
-
只能接受关键字传参
-
基本形式
def func(**kwargs): print(kwargs) func(k1 = 1,k2 = 'alex') #kwargs = {'k1':1,'k2':'alex'} func(**{'k1':'v1','k2':'v2'}) #kwargs = {'k1':'v1','k2':'v2'} #注意实参里有**和没有的区别
-
-
综合运用(*args和**kwargs一起使用)
def func(*args,**kwargs): print(args,kwargs) func(1,2,3,4,k1 = 1,k2 = 2) #args = (1,2,3,4),kwargs = {'k1':1,'k2':2} func(*[1,2,3],**{'k1':'v1','k2':'v2'}) #args = (1,2,3),kwargs = {'k1':'v1','k2':'v2'}
-
参数相关重点
-
定义函数
#情况一: def func(a,b): pass #情况二: def func(a,b = None): pass #情况三: def func(*args,**kwargs): pass
-
调用函数:位置参数 > 关键字参数
-
-
练习题
# 1. 请写一个函数,函数计算列表 info = [11,22,33,44,55] 中所有元素的和。 def get_sum(): info = [11,22,33,44,55] data = 0 for item in info: data += item print(data) get_sum()
# 2. 请写一个函数,函数计算列表中所有元素的和。 def get_list_sum(a1): data = 0 for item in a1: data += item print(data) get_list_sum([11,22,33]) get_list_sum([99,77,66]) v1 = [8712,123,123] get_list_sum(v1)
# 3. 请写一个函数,函数将两个列表拼接起来。 def join_list(a1,a2): result = [] result.extend(a1) result.extend(a2) print(result) join_list([11,22,33],[55,66,77]
# 4. 计算一个列表的长度 def my_len(arg): count = 0 for item in arg: count += 1 print(count) v = [11,22,33] my_len(v) len(v)
# 5. 发邮件的示例 def send_email(role,to): template = "要给%s%s发送邮件" %(role,to,) print(template) user_input = input('请输入角色:') if user_input == '管理员': send_email('管理员','xxxx@qq.com') elif user_input == '业务员': send_email('业务员','xxxxo@qq.com') elif user_input == '老板': send_email('老板','xoxox@qq.com')
3.2.3 返回值
-
作用
- 返回值
- 终止函数的执行
-
基本形式
def func(arg): 代码 #函数内容 return 9 #返回值为9,默认:return None val = func('ads') #设置一个变量接收返回值 #特殊情况: def func(): return 2,3,'alex' #返回是一个元组 val = func() print(val) #(2,3,'alex',)
-
返回值相关重点
-
函数没有返回值,默认返回:None
-
函数内部执行过程一旦遇到return就终止
-
return可以返回任意类型
-
练习题
# 1. 写函数,计算一个列表中有多少个数字,打印: 列表中有%s个数字。 # 提示:type('x') == int 判断是否是数字。 # 方式一: def get_list_counter1(data_list): count = 0 for item in data_list: if type(item) == int: count += 1 msg = "列表中有%s个数字" %(count,) print(msg) get_list_counter1([1,22,3,'alex',8]) # 方式二: def get_list_counter2(data_list): count = 0 for item in data_list: if type(item) == int: count += 1 return count v = get_list_counter1([1,22,3,'alex',8]) msg = "列表中有%s个数字" %(v,) print(msg)
# 2. 写函数,计算一个列表中偶数索引位置的数据构造成另外一个列表,并返回。 # 方式一: def get_data_list1(arg): v = arg[::2] return v data = get_data_list1([11,22,33,44,55,66]) # 方式二: def get_data_list2(arg): v = [] for i in range(0,len(arg)): if i % 2 == 0: v.append(arg[i]) return v data = get_data_list2([11,22,33,44,55,66])
# 3. 读取文件,将文件的内容构造成指定格式的数据,并返回。 """ a.log文件 alex|123|18 eric|uiuf|19 ... 目标结构: a. ["alex|123|18","eric|uiuf|19"] 并返回。 b. [['alex','123','18'],['eric','uiuf','19']] c. [ {'name':'alex','pwd':'123','age':'18'}, {'name':'eric','pwd':'uiuf','age':'19'}, ] """ def a(): info = [] with open('a.log',mode='r',encoding='utf-8') as f: for line in f: line = line.strip() info.append(line) return info def b(): info = [] with open('a.log',mode='r',encoding='utf-8') as f: for line in f: line = line.strip() v = line.split('|') info.append(v) return info def c(): info = [] with open('a.log',mode='r',encoding='utf-8') as f: for line in f: line = line.strip() list = line.split('|') v = {} v['name'] = list[0] v['pwd'] = list[1] v['age'] = list[2] info.append(v) return info date1 = a() date2 = b() date3 = c() print(date1,date2,date3)
-
-
数据类型中的方法有没有返回值总结
-
无返回值
#示例: v = [11,22,33] v.append(99)
-
仅有返回值
#示例一: v = "alex" result = v.split('l') #示例二: v = {'k1':'v2'} result1 = v.get('k1') result2 = v.keys()
-
有返回值 + 修改数据
#示例: v = [11,22,33] result = v.pop() # 将被删除的数据赋值给result
-
常用需要记住的
-
str
①. strip(),返回字符串
②. split(),返回列表
③. replace(),返回字符串
④. join(),返回字符串
-
list
① . append(),无
②. insert(),无
③. pop(),返回要删除的数据
④. remove(),无
⑤. find() / index(),返回索引位置的数据
-
dict
①. get,返回缩影键的值
②. keys(),返回字典所有的键
③. values(),返回字典所有的值
④. items(),返回字典所有的键值对
-
-
3.2.4 总结
-
函数的基本结构:
#情况一 def f1(): 函数内容 f1() #情况二 def f2(a): 函数内容 f2(1) #情况三 def f3(): 函数内容 return v1 = f3() #情况四 def f4(a1,a2): 函数内容 return a1+a2 v2 = f4(1,7)
-
函数内部的数据是否会混乱?
- 函数的内部执行相互之间不会混乱
- 执行完毕 + 内部元素不被其他人使用 =>销毁
3.3 函数小高级
3.3.1 函数名可以当做变量来使用
#示例一:
def func():
print(123)
func_list = [func, func, func]
# func_list[0]()
# func_list[1]()
# func_list[2]()
for item in func_list:
v = item()
print(v)
#示例二:
def func():
print(123)
def bar():
print(666)
info = {'k1': func, 'k2': bar}
info['k1']()
info['k2']()
#注意区别:
def func():
return 123
func_list1 = [func,func,func]
func_list2 = [func(),func(),func()]
print(func_list1)
print(func_list2)
3.3.2 函数可以当做参数进行传递
#示例:
def func(arg):
v1 = arg()
print(v1)
def show():
print(666)
result = func(show)
print(result)
面试题
#面试题:多个函数的调用
def func():
print('话费查询')
def bar():
print('语音沟通')
def base():
print('业务办理')
def show():
print('流量查询')
def test():
print('人工服务')
info = {
'f1': func,
'f2': bar,
'f3':base,
'f4':show,
'f5':test
}
choice = input('请选择要选择功能:')
function_name = info.get(choice)
if function_name:
function_name()
else:
print('输入错误')
3.3.2 匿名函数:lambda表达式
-
作用:用于简单表达的函数
-
基本形式
#三元运算,为了解决简单的if else的情况 if 1 == 1: a = 123 else: a = 456 #用三元运算表示: a = 123 if 1 == 1 else 456 #lambda表达式,为了解决简单函数的情况 def func(a1,a2): return a1 + a2 #用lambda表达式表示: func = lambda a1,a2: a1+a2 #隐含了return
-
重点:
- lambda表达式只能用一行表示函数
- 用lambda表达式表示函数时,无法设置新变量,只能用哪个参数做变量
- 列表多有的方法基本上都是返回None,字符串的所有方法基本上都是返回新值
-
练习题
# 练习题1 USER_LIST = [] def func0(x): v = USER_LIST.append(x) return v result = func0('alex') print(result) #None
# 练习题2 def func0(x): v = x.strip() return v result = func0(' alex ') print(result) #'alex'
# 练习题3 USER_LIST = [] func1 = lambda x: USER_LIST.append(x) v1 = func1('alex') print(v1) #None print(USER_LIST) #['alex']
# 练习题4 func1 = lambda x: x.split('l') v1 = func1('alex') print(v1) #['a','ex']
# 练习题5 func_list = [lambda x:x.strip(), lambda y:y+199,lambda x,y:x+y] v1 = func_list[0]('alex ') print(v1) #'alex' v2 = func_list[1](100) print(v2) #299 v3 = func_list[2](1,2) print(v3) #3
3.4 函数中高级
3.4.1 函数可以做返回值
#示例:
def func():
print(123)
def bar():
return func
v = bar()
v()
3.4.2 闭包
-
概念:为函数创建一块区域并为其维护自己数据,方便以后执行时调用
-
应用场景:
- 装饰器
- SPLAchemy源码
#示例: name = 'oldboy' def bar(name): def inner(): print(name) return inner v1 = bar('alex') # { name=alex, inner } # 闭包,为函数创建一块区域(内部变量供自己使用),为他以后执行提供数据。 v2 = bar('eric') # { name=eric, inner } v1() # alex v2() # eric #区分: # 不是闭包 def func1(name): def inner(): return 123 return inner # 是闭包:封装值 + 内层函数需要使用。 def func2(name): def inner(): print(name) return 123 return inner
-
练习题
#第一题 name = 'alex' def base(): print(name) def func(): name = 'eric' base() func() # eric
# 第二题 name = 'alex' def func(): name = 'eric' def base(): print(name) base() func() # eric
# 第三题 name = 'alex' def func(): name = 'eric' def base(): print(name) return base base = func() base() # eric #注意:函数在何时被谁创建?
#示例: # 第四题 info = [] def func(): print(item) for item in range(10): info.append(func) info[0]() # 9
-
面试题
#面试题 info = [] def func(i): def inner(): print(i) return inner for item in range(10): info.append(func(item)) info[0]() # 0 info[1]() # 1 info[4]() # 4
3.4.3 高阶函数
- 把函数当做参数传递
- 把函数当做返回值
- 注意:对函数进行赋值
3.5 内置函数
函数分为自定义函数赫尔内置函数
3.5.1 强制转换类
- int() / str() / bool() / list() / tuple() / dict() / set()
3.5.2 输入输出类
- input() / print()
3.5.3数学相关类
-
abs(),计算绝对值
v = abs(-1) print(v)
-
sum(),求和
v = [1,2,3,4,5,6,7,8] print(sum(v))
-
float(),转换为浮点型(小数)
v = 55 v1 = float(55) print(v1) #55.0
- 补充:int(5.5),只保留整数
-
max(),找到最大值
v = [1,2,311,21,3,] result = max(v) print(result)
-
min(),找到最小值
v = [1,2,311,21,3,] result = min(v) print(result)
-
divmod(),去两数相除的商和余
#示例: a,b = divmod(1001,5) print(a,b) #a=200,b=1
-
补充:分页展示数据:
# 练习题 请通过分页对数据进行展示 """ 要求: 每页显示10条数据 让用户输入要查看的页面:页码 """ USER_LIST = [] for i in range(1,836): temp = {'name':'你-%s' %i,'email':'123%s@qq.com' %i } USER_LIST.append(temp) # 数据总条数 total_count = len(USER_LIST) # 每页显示10条 per_page_count= 10 # 总页码数 max_page_num,a = divmod(total_count,per_page_count) if a>0: max_page_num += 1 while True: pager = int(input('要查看第几页:')) if pager < 1 or pager > max_page_num: print('页码不合法,必须是 1 ~ %s' %max_page_num ) else: start = (pager-1) * per_page_count end = pager * per_page_count data = USER_LIST[start:end] for item in data: print(item)
-
-
pow(),指数
v = pow(2,3) #相当于2**3 print(v) # 8
-
round() ,保留几位小数,默认保留整数,还会四舍五入
v = round(1.127,2) #第二个数代表保留几位小数,默认是None print(v) # 1.13 四舍五入
3.5.4 进制转换类
-
bin():将十进制转换成二进制
v = 10 print(bin(v))
-
oct():将十进制转换成八进制
v = 10 print(oct(v))
-
int():将其他进制转换成十进制(base默认是10)
-
二进制转换成十进制
# 二进制转化成十进制 v1 = '0b1101' result = int(v1,base=2) #base=2说明读取的是二进制 print(result)
-
八进制转换成十进制
# 八进制转化成十进制 v1 = '0o1101' result = int(v1,base=8) print(result)
-
十六进制转化成十进制
# 十六进制转化成十进制 v1 = '0x1101' result = int(v1,base=16) print(result)
-
-
hex():将十进制转换成十六进制
v = '10' print(hex(v))
-
面试题(1字节等于8位)
# 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。 ip = "192.168.12.79" # 001010010 . 001010010 . 001010010 . 001010010 ip_list = ip.split('.') # ['192','168','12','79'] result = [] for item in ip_list: result.append(bin(int(item))) print(','.join(result))
# 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制: # 0010100100001010010001010010001010010 -> 十进制的值。 # 3232238671 ip = '192.168.12.79' v = ip.split('.') info = [] for i in v: date = str(bin(int(i))) if len(date) > 10: date = date[-8:] else: count = 10 - len(date) date = date.replace('0b','0'*count) info.append(date) val = "".join(info) a = int(val,base=2) print(a)
3.5.5 与类相关类
-
type():查看数据类型
class Foo: pass obj = Foo() if type(obj) == Foo: print('obj是Foo类的对象')
-
issubclass(类,或其基类):判断前一个类是否是后一个类或其基类的子类
class Base: pass class Base1(Base): pass class Foo(Base1): pass class Bar: pass print(issubclass(Bar,Base)) print(issubclass(Foo,Base))
-
isinstance(对象,类或其基类):判断一个对象是否是一个类或其基类的实例(对象)
- 注意:判断一个对象是否是一个类的实例(对象),一定要用type,不要使用instance
class Base(object): pass class Foo(Base): pass obj = Foo() print(isinstance(obj,Foo)) # 判断obj是否是Foo类或其基类的实例(对象) print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象)
-
super().方法名():
- 单继承:根据self对象所属的类的继承关系,按照顺序依次找方法并执行(找到第一个为止)【这只是表象】
- 多继承:不是根据父类的继承顺序来查找函数,而是根据mro的顺序来查找函数
class A: def func(self): print('A') class B(A): def func(self): print('B') super().func() class C(A): def func(self): print('C') super().func() class D(B,C): def func(self): print('D') super().func() D().func()
class Base(object): def func(self): super().func() # 根据self对象所属类的继承关系,按照顺序挨个找func(除去此func函数)方法并执行(找到第一个为止) print('base.func') class Bar(object): def func(self): print(bar3) class Foo(Base,Bar): # Foo -> Base -> Bar pass obj = Foo() obj.func()
3.5.6 编码相关
-
chr():将十进制数字转换成ascii编码中对相应的字符串
-
ord():根据字符在ascii编码中找到对应的十进制
-
应用实例(随机验证码的生成)
#应用:生成随机验证码 import random # 导入一个模块 def get_random_code(length=6): data = [] for i in range(length): v = random.randint(65,90) data.append(chr(v)) return ''.join(data) code = get_random_code() print(code)
3.5.7 高级的内置函数
-
zip():拉链,拉链方法一一对应(算不上高级)
val = zip(('a','b','c'),(1,2,3)) print(list(val)) #---> [('a',1),('b',2),('c',3)]
-
map(函数,可迭代对象):一起执行
- 循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行得到的结果保存到行的列表中(可强制转换list,也可for循环遍历),并返回
#示例一(常规函数): def func(v): return v + 100 v1 = [11,22,33,44] result = map(func,v1) print(result) #示例二(lambda): v1 = [11,22,33,44] result = map(lambda x:x+100,v1) print(list(result))
-
filter(函数,可迭代对象):进行筛选
-
对于可迭代对于可迭代对象中的元素进行筛选,最终获取符合条件的序列。
#示例: v1 = [11,22,33,'asd',44,'xf'] def func(x): if type(x) == int: return True return False result = filter(func,v1) print(list(result)) # [11, 22, 33, 44] # 用lambda表达式: result = filter(lambda x: True if type(x) == int else False ,v1) print(list(result)) # 相当于: result = filter(lambda x: type(x) == int ,v1) print(list(result))
-
-
reduce(函数,可迭代对象):得到结果
-
与map和filter不同,reduce在最新的py3版本中移除内置函数,需要执行时调用,另外输入是两个值,作用是输入一堆元素,输出一个值
-
用传给reduce中的函数func(有两个参数)先对第一、二个元素进行操作,得到的结果再与第三个数据用func函数运算,最后得到一个结果
import functools #【reduce 在python3的内置函数中被移除,需要导入functools 】 v1 = ['wo','hao','e'] def func(x,y): return x+y result = functools.reduce(func,v1) print(result) result = functools.reduce(lambda x,y:x+y,v1) print(result)
-
3.5.8 其他内置函数
- len():计算长度
- open():打开文件
- range():
- id():查看内存地址
3.6 作用域
3.6.1 分类
-
全局作用域:在python中,相当于一个py文件
- 全局作用域中的变量称为全局变量
- 全局变量必须大写(潜规则)
-
局部作用域:在python中,相当于一个函数
- 局部作用域中的变量称为局部变量
- 局部变量则用小写
USER_LIST = [11,22,3] #全局变量
def func():
name = 'asdf' #局部变量
USER_LIST.append(12)
USER_LIST.append(name)
func()
print(USER_LIST)
3.6.2 递归
-
递归就是自己调用自己。(效率低)
def func(): print(1) func() func()
# 递归的返回值 def func(a): if a == 5: return 100000 return = func(a+1) + 10 v = func(1) print(v) name = 'alex' def func(): def inner(): print(name) return inner v =func()
3.6.3 总结
-
在python中,一个函数就是一个作用域
-
在作用域中查找数据规则:
- 优先在自己作用域里面找数据
- 自己没有就去‘父级’中找,没有就去‘父级’的‘父级’中找,直到找到全局作用域
- 如果最后找到全局作用域中也没有就会报错
- 寻找时注意:父级作用域中的只是到底是什么
#示例一: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) func() # 9
#示例二: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) x1() func() # 9 8
#示例三: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) print(x) x1() func() # 9 9 8
#示例四: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) x1() print(x) func() # 9 8 9
#示例五: x = 10 def func(): x = 9 print(x) def x1(): print(x) x1() print(x) func() # 9 9 9
#示例六: x = 10 def func(): x = 8 print(x) def x1(): print(x) x = 9 x1() x = 10 print(x) func() # 8 9 10
#示例七: x = 10 def func(): x = 8 print(x) def x1(): print(x) x1() x = 9 x1() x = 10 print(x) func() # 8 8 9 10
-
对于自作用域:
-
只能找到‘父级’中的值,默认无法重新为‘父级’的变量进行重新赋值
-
如果非要对’父级‘变量进行重新赋值,使用呢global / nonlocal 进行强制赋值
- global:直接找到指定的全局变量,在进行重新赋值,其他的不改
- nonlocal:只找到‘父级’的变量,进行重新赋值,其他的不改
- 建议:一般不用,以免造成代码混乱
#global示例: name = 'oldboy' def func(): name = 'alex' def inner(): global name #直接找到全局的name name = 'abc' #再进行重新赋值 inner() print(name) #'alex' func() print(name) #'abc'
#nonlocal示例: name = "oldboy" def func(): name = 'alex' def inner(): nonlocal name #找到上一级的name name = 'abc' #再进行重新赋值 inner() print(name) #'abc' func() print(name) #"oldboy"
-
3.7 推导式
3.7.1 列表推导式
-
目的:方便生成一个列表
-
格式:
v1 = [i for i in 可迭代对象 ] v2 = [i for i in 可迭代对象 if 条件 ] #条件为true才进行append
# 示例: v1 = [ i for i in 'alex' ] v2 = [i+100 for i in range(10)] v3 = [99 if i>5 else 66 for i in range(10)] def func(): return 100 v4 = [func for i in range(10)] v5 = [lambda : 100 for i in range(10)] result = v5[9]() v6 = [lambda :i for i in range(10)] result = v6[5]()
面试题
# 新浪微博面试题 v7 = [lambda x:x*i for i in range(10)] # 1.请问 v7 是什么? # 2.请问 v7[0](2) 的结果是什么? # 面试题 def num(): return [lambda x:i*x for i in range(4)] # 此时i已经变成了3 # num() -> [函数,函数,函数,函数] print([ m(2) for m in num() ]) # [6,6,6,6]
3.7.2 集合推导式
-
目的:方便生成一个集合
-
格式
v1 = { i for i in 'alex' }
3.7.3 字典生成器
-
目的:方便生成一个字典
-
格式:
v1 = { 'k'+str(i):i for i in range(10)}
3.7.4 生成器推导式
# 列表推导式,立即循环创建所有元素
"""
def func():
result = []
for i in range(10):
result.append(i)
return result
v1 = func()
"""
v1 = [i for i in range(10)]
print(v1)
# 生成器推导式,创建了一个生成器,内部循环为执行
"""
def func():
for i in range(10):
yield i
v2 = func()
"""
v2 = (i for i in range(10))
for item in v2:
print(item)
# 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
# 列表是可变类型的数据类型,内部不支持哈希算法,所以在查找时比较费时间
# 元组是不可变类型的数据类型,内部支持哈希算法,所以在查找时时间耗损比较小
import time
l_start = time.time()
list_ = [i for i in range(1000000)]
l_end = time.time()
print(l_end - l_start)
print('*'*30)
d_start = time.time()
dict_ = (i for i in range(1000000))
d_end = time.time()
print(d_end - d_start)
# 0.060662031173706055 列表
# 0.0 元组
3.8 装饰器
3.8.1 目的
- 在不改变函数内部代码的基础上,在执行函数之前和之先动执行某个功能
3.8.2 应用场景
- 想要为函数扩展功能时,可以选择用装饰器
3.8.3 基本装饰器
-
基本格式:
def wrapper(func): def inner(*args,**kwargs): v = func(*args,**kwargs) return v return inner # 重点: # 第一步:执行wrapper函数并将下面的函数参数传递,相当于:wrapper(index) # 第二步:将wrapper的返回值重新赋值给下面的函数名。 即:index = wrapper(index) @wrapper def index(*args,**kwargs): print(123) return 666 print(index)
-
总结:
-
编写格式:
def 外层函数(参数): def 内层函数(*args,**kwargs) return 参数(*args,**kwargs) return 内层函数
-
应用格式:
@外层函数 def index(): #要装饰的函数 pass index()
-
装饰器的编写:
# 装饰器的编写 def x(func): def y(): # 前 ret = func() # 后 return ret return y # 装饰器的应用 @x def index(): return 10 # 执行函数,自动触发装饰器了 v = index() print(v)
-
示例:
def func(arg): def inner(): print('before') v = arg() print('after') return v return inner @func def index(): print('123') return '666' # 示例一 v1 = index() # 执行index函数,打印123并返回666赋值给v1. # 示例二 v2 = func(index) # v2是inner函数,arg=index函数 index = 666 v3 = v2() # 示例三 v4 = func(index) index = v4 # index ==> inner index() # 示例四 index = func(index) index()
-
3.8.4 带参数的装饰器
-
应用场景:flask框架 / Django缓存 / 写装饰器实现被装饰器的函数要执行N次
# 第一步:执行 ret = xxx(index) # 第二步:将返回值赋值给 index = ret @xxx def index(): pass # 第一步:执行 v1 = uuu(9) # 第二步:ret = v1(index) # 第三步:index = ret @uuu(9) def index(): pass
-
普通装饰器和带参装饰器的区别
# 普通装饰器 def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner @wrapper def index(): pass # 带参数装饰器 def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @x(9) def index(): pass
-
练习题
# 习题一: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): v = [] for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 v.append(data) return v return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
# 习题二: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回最后一次执行的结果【面试题】 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
# 习题三: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回执行结果中最大的值。 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): value = 0 for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 if data > value: value = data return value return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
3.9 迭代器
3.9.1 基本知识
-
用途:对某种对象(str list tuple dict set)中的元素进行逐一获取
-
表象:具有
__iter__
方法切每次调用都会获取可迭代对象中的元素(从前到后以一个一个获取) -
示例:
-
列表转换成迭代器:
v = iter([1,2,3,4,5,6]) v = [1,2,3,4,5,6].__iter__()
-
迭代器想要获取每个值:反复调用 val = v.
__next_
()v1 = [11,22,33,44] # 列表转换成迭代器 v2 = iter(v1) # 迭代器获取每个值 result1 = v2.__next__() print(result1) # 11 result2 = v2.__next__() print(result2) # 22 result3 = v2.__next__() print(result3) # 33 result4 = v2.__next__() print(result4) # 44 result5 = v2.__next__() print(result5) # 报错:Stoplteration 表示已经迭代结束
-
-
for循环:运用了迭代器
v1 = [11,22,33,44] # 1.内部会将v1转换成迭代器 # 2.内部反复执行 迭代器.__next__() # 3.取完不报错 for item in v1: print(item)
3.9.2 可迭代对象
-
表象:可以被for循环的对象就可以称为可迭代对象
-
如何让一个对象变成可迭代对象?
-
在类中实现
__iter__
方法并且返回一个迭代器(生成器)# 示例一: class Foo: def __iter__(self): return iter([1,2,3,4]) obj = Foo() # 示例二: class Foo: def __iter__(self): yield 1 yield 2 yield 3 obj = Foo()
-
-
注意:只要能被for循环,就去它的内部看
__iter__
方法
3.10 生成器
3.10.1 基本知识
-
可以理解为:函数的变异、特殊的迭代器、特殊的可迭代对象
-
生成器的作用:生成数据、迭代
-
示例:
# 生成器函数(内部是否包含yield) def func(): print('F1') yield 1 print('F2') yield 2 print('F3') yield 100 print('F4') # 函数内部代码不会执行,返回一个 生成器对象 。 v1 = func() # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。 for item in v1: print(item)
3.10.2 关键字
-
yield:判断函数是否是生成器
-
yield from:从当前生成器函数跳转到其他生成器函数中,执行结束后再回到原函数继续执行下面的代码
def base(): yield 88 yield 99 def func(): yield 1 yield 2 yield from base() # 跳到base函数 yield 3 result = func() for item in result: print(item) # 1 2 88 99 3
3.10.3 总结
-
重点:
-
函数中如果存在yield,那么该函数就是一个生成器函数
-
调用生成器函数会返回一个生成器
def func(): yield 1 result = func() print(type(result)) # <class 'generator'> print(result) # <generator object func at 0x0000024845623ED0> print(list(result)) # [1] # 不管yield返回一个值还是多个值,其类型都是生成器对象,要打印时,可以强制转换成列表,或者for循环
-
生成器只有被for循环时,生成器函数你不的代码才会执行,每次循环都会获取yield返回的值
-
-
建议:
-
生成器函数中最好不要有return
-
如果需要终止生成器函数中的循环,可以用return
def func(): count = 1 while True: yield count count += 1 if count == 100: return val = func() for item in val: print(item)
-
-
生成器示例:读取大文件内容
def func(): # 分批去读取文件中的内容,将文件的内容返回给调用者。 cursor = 0 while True: f = open('db', 'r', encoding='utf-8') # 通过网络连接上redis # 代指 redis[0:10] f.seek(cursor) data_list =[] for i in range(10): line = f.readline() if not line: return data_list.append(line) cursor = f.tell() f.close() # 关闭与redis的连接 for row in data_list: yield row for item in func(): print(item)
3.11 异常处理
3.11.1 基本格式
try:
val = input('请输入数字:')
num = int(val)
except Exception as e:
print('操作异常')
- 注意:放在位置的不同有不同的效果。灵活运用,避免程序报错和崩溃
3.11.2 finally的运用
def:
try:
int('asdf')
except Exception as e:
print(e)
return 123
finally:
print('1')
func()
#即使return finally最后也会执行
3.11.3 主动触发异常
try:
int('123')
raise Exception('dsfsegsdg') #主动触发异常
except Exception as e:
print('111')
3.11.4 自定义异常(raise)
class MyException(Exception):
def __init__(self,message):
super().__init__()
self.message = message #在Exception 类中 的初始化 加入一行 self.message = message
try:
raise MyException('asdf')
except MyException as e: #此时 e = MyException('asdf)
print(e.message)