第五章 函数

5.1 三元运算(三目运算)

三元运算的基本结构:

v =   前面的值 if 条件  else 后面
条件为真 v=前面的值,条件为假v=后面的值
if 条件:
    v = '前面'
 else:
    v = '后面'
例题:
让用户输入值,如果值是整数,则转换成整数,否则赋值为none
data = input('')
value = int(data) 
True if datea.isdecimal()  else none

5.2 函数

截止目前:都是面向过程编程。其特点是可读性差/可重用性差

为了增加代码的重复利用,可读性,所以引入函数

面向过程编程

user_input = input('请输入角色:')

if user_input == '管理员'pass   #给管理员发邮件,10行代码
if user_input == '业务员':
   pas   s#给业务员发邮件,10行代码  
 if user_input == '老板'pass   #给老板发邮件,10行代码

对于函数编程:

  1. 本质:将N行代码拿到别处并给它起个名字,以后通过名字可以找到这段代码并执行

  2. 场景:

    1. 代码重复执行

    2. 代码量特别多超过一屏,可以选择通过函数进行代码分分割

5.2.1函数的基本结构

def 函数名(形参):

#函数的定义
def 函数名():  函数名的命名规则和变量名命名规则一样
    函数内容
    pass
    
 函数的执行
 函数名()
例题:
def get_list_first_data():  
    v = [11,22,33,44]
    print(v[0])
get_list_first_data()
##注意:函数如果不被调用,则内部代码永远不会被执行

5.2.2 函数的参数

参数:

  1. 形参 : def 函数名(形参)

    1. 基本的参数:def func(a,b) pass

    2. 默认值:def func(a,b=123) pass (注意:默认值如果是不可变类型,随便玩;可变类型:有坑)

    3. 无敌:*args,**kwarges接受任意的位置参数和关键字参数

  2. 实参

    1. 位置传参

    2. 关键字传参 (位置传参永远在关键字传参前面)

例题:
#1.请写一个函数,函数计算列表info = [11,22,33,44,55]中所有元素的和

def get_sum():
    info = [11,22,33,44,55]
    data = 0
    for i in info:
        data =data +i
    print(data)
get_sum()

#2请写一个函数,函数计算列表中所有元素的和
def get_list_sum(a):  #a是形参
    data = 0
    for item in a:
        data += item
    print(data)
get_list_sum([11,22,33,44]) #列表是实参
get_list_sum([99,77,33,44])
 # 3请写一个函数,函数将两个列表拼接起来
 def join_list(a,b):
    result = []
    result.extend(a)
    result.extend(b)
    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,334,]
my_len(v)

#5 发送邮件
def send_email(role,to):
    template = '要给%s%s发送邮件'%(role,to,)
    print(template)
    
user_input = input('请输入角色:')
if user_input == '管理员':
    send_email('管理员','管理员邮箱')
if user_input == '业务员':
    send_email('业务员','业务员邮箱')
if user_input == '老板':
    send_email('老板','老板邮箱')

5.2.3 返回值

  1. 函数没有返回值,默认返回None

  2. 函数内部执行过程中遇到return,就终止

def  func(arg):
     #....
     return 9 #返回值为9,默认:return None
     返回值可以是列表、字典等
     
val = func('dedgggggg')

def func():
    return '完成' # 函数每次执行到此,就返回,不执行下面的代码
    for i in range(10):
        print(i)
func()


v = func()
print(v)
#特殊:返回元组

def func():
    for i in range(10):
        print(i)
        return '完成'
func()    #0

练习题

#1.让用户输入一个字符串,计算字符串中有多少个大写的A,有多少个A就在文件a.txt中写多少个’李奇‘
def get_char_count(data):
    sum_counter = 0
    for i in data:
        if i  =='A':
            sum_counter +=1
    return sum_counter

def write_file(line):
    if len(line) == 0:
        return False  #函数执行过程中一旦遇到return,则停止执行
    with open('a.txt',mode = 'w',encoding= 'utf-8')as f:
        f.write(line)
    return True

content = input('请输入:')
counter = get_char_count(content)
write_data = '李奇'* counter
status = write_file((write_data))
if status:
    print('写入成功')
else:
    print('写入失败')
练习题:

1.写函数,计算一个列表中有多少个数字,打印:列表中有%s个数字

def list_number(data):
    total = 0
    for item in data:
        if type(item) == int:
            total +=1
    msg = '列表中有%s个数字'%(total,)
    print(msg)
list_number([1,2,34,'alxe'])

def list_number(data):
    total = 0
    for item in data:
        if type(item) ==int:
            total +=1
    return total
v = list_number([1,2,3,'alxe',5,6])
msg = '列表中有%s个数字'%(v,)
print(msg)

#2写函数,计算一个列表中偶数索引位置的数据构成另外一个列表,并返回

def list_data(arg):
    v = arg[::2]
    return v
data = list_data([1,2,3,4,5,6])


def list_data(arg):
    v = []
    for i in range(0,len(arg)):
        if i % 2 == 0:
            v.append(i)
    return v 
data = list_data([1,3,4,5])


#利用参数,读取文件,将文件的内容构造成指定格式的数据,并返回
'''
a.txt文件
alex|123|18
eric|uiuf|19

目标结构
['alex|123|18','eric|uiuf|19']并返回
[['alex','123',18],['eric','uiuf',19]
[{'name':'alex','pwd':'123','age':18},
  {'name':'eric','pwd':'uiuf','age':19}]
def read_line(arg):
     with open('a.txt', mode='r', encoding='utf-8')as f:
        data = f.read()
        list = data.split('\n')
        print(list)
line = read_line(1)
  
def read_line(arg):
    with open('a.txt',mode='r',encoding='utf-8') as f:
        data = f.read()
        list = data.split('\n')
        now_list = []
        now_list.append(list[0].split('|'))
        now_list.append(list[1].split('|'))
        print(now_list)
line = read_line(1)
'''

def read_line(arg):
    with open('a.txt',mode='r',encoding='utf-8') as f:
        data = f.read()
        list = data.split('\n') #[alex|123|18,eric|uiuf|19]
        now_list = []
        now_list.append(list[0].split('|'))
        now_list.append(list[1].split('|'))  #[alex,123,18],[eric,uiuf,19]]
        keys = ['name','pwd','age']
        list2 = []
        dic = {}
        for l in now_list:
            for i in range(len(l)):
                dic[keys[i]] = l[i]
            list2.append(dic)
        print(list2)
line = read_line(1)

数据类型中的方法到底有没有返回值?

1.无返回值

v = [11,22,44]
v.append(99)#无返回值

2.仅有返回值:内部没有修改

v = 'alex'
result = v.split('l')

v = {'k1':v1}
result1 = v.get('k1')
result2= v.keys()

3.有返回值+内部修改数据

v = [11,22,333]
result = v.pop()

4.常用需要记住

4.1 str

  1. strip,有,返回字符串

  2. split ,有,返回列表

  3. replace,返回字符串

  4. upper 返回字符串

  5. lower 返回字符串

  6. join 返回字符串

4.2 列表

  1. append,无

  2. insert 无

  3. pop 返回要删除的数据

  4. remove 无

  5. find/index 返回索引的位置

4.3dict

  1. get 有

  2. keys有

  3. values 有

  4. items 有 

5.3 参数

基本参数知识:可以是任意个数也可以是任意类型

def func(a1,a2,a3):
    print(a1,a2,a3)
 
func(1,'asdf',True)

5.3.1 位置参数(调用函数并传入参数)(执行)

def func(a1,a2):
    print(a1,a2)
    
func(1,2)

5.3.2 关键字传参(把形参的名称放到值参中)(执行)

def func(a1,a2):
    print(a1,a2)

func(a2=99,a1= 1)

#关键字传参和位置传参可以混合使用,位置传入参数一定要在前面,关键字参数一定在后,总参数个数不变(先位置参数后关键字参数)
def func(a1,a2,a3):
    print(a1,a2,a3)
func(1,2,a3=9)  #输出1 2 9
func(1,a2=2,a3=9)
func(a1=1,a2=2,a3=9)
func(a1=1,2,9)#错误

注意:关键字传参和位置传参可以混合使用,位置传入参数一定要在前面,关键字参数一定在后,总参数个数不变(先位置参数后关键字参数)

5.3.3 默认参数【自定义】

def func(a1,a2=9): #=表示可传可不传,不传参数时等于默认值
    pass


func函数可以接收两个参数,调用函数进行传值时:
func(1,2)
func(1,a2=10)
func(a1=123,a2=999)
func(1)

def func(a1,a2,a3=4):
    print(a1,a2,a3)
# func(11,22) #11 22 4
func(11,22,10) #11 22 10


def file_write(file_path,content='\n'):  #flie_path是文件路径,content是写入的内容,content后面不写是默认换行
    pass

def file_read(file_path, num=1):    ##flie_path是文件路径,num是读的第几行,写入1就是第一行
    pass

5.3.4 万能参数(参数打散)

1.*args(位置参数):可以接收任意个数的位置参数,并将参数转换成元组,不支持关键字传参,只支持位置传参

    a:实参有*

 def func(*args):  #* 指的是可以接收多个参数,不确定函数接收多少个参数的时候用,不支持关键字传参,只支持位置传参
    print(args)
  func(*(11,22,33,44,55))  #args=(11, 22, 33, 44, 55)将元素循环添加到元组
func(*[11,22,33,44])#列表也是一样

    b:实参不带*

def func(*args):
    print(args)
 func((11, 22, 33, 44, 55)) args=((11, 22, 33, 44, 55),)
 
## 只能用位置参数

2.**kwargs(关键字参数):可以接收任意个数的关键字参数,并将参数转换成字典,只能用关键字传参

    a:调用函数无**

def func(**kwargs):
      print(**kwargs)
  func(k1=1) #{'k1': 1}
  func(k1=1,k2='alex')  #{'k1': 1, 'k2': 'alex'}

   b:调用函数有**

def func(**kwargs):
    print(kwargs)
func(k1=1) #kwargs={'k1': 1}
func(**{'k1':'v1','k2':'v2'})  #kwargs={'k1': 'v1', 'k2': 'v2'}
func(k1={'k1':999,'k2':777},k2='alex') #kwargs={'k1': {'k1': 999, 'k2': 777}, 'k2': 'alex'}

3.综合应用:无敌+无敌

def func(*args,**kwargs):
    print(args,kwargs)
func(1,2,3,4,k1=2,k2=2,k4=999)  #args=(1, 2, 3, 4) kwargs={'k1': 2, 'k2': 2, 'k4': 999}

func(*(1,2,3,4),k1=2,k2=2,k4=999) #args=(1, 2, 3, 4) kwargs={'k1': 2, 'k2': 2, 'k4': 999}
func(11,22,33,*(1,2,3),**{'k1':1,'k2':2}) #args=(11, 22, 33, 1, 2, 3) kwargs={'k1': 1, 'k2': 2}

func(11,22,33,*(1,2,3),k11='alex',**{'k1':1,'k2':2})#args=(11, 22, 33, 1, 2, 3) kwargs={'k11': 'alex', 'k1': 1, 'k2': 2}

练习题:

def func(*args):  #* 指的是可以接收多个参数,不确定函数接收多少个参数的时候用,一般*加args
    print(args)
func(1) #args=(1,)
func(1,2) #args=(1, 2)
func(1,2,[11,22],123123,999,True,'alex') #args=(1, 2, [11, 22], 123123, 999, True, 'alex')

func((11,22,33,44,55))  #args=((11, 22, 33, 44, 55),)#元组套元组
func(*(11,22,33,44,55))  #args=(11, 22, 33, 44, 55)#将元素循环添加到元组,打散

def func(a1,*args,a2): #args后面还有参数时,a2必须要用关键字传参
    print(a1,args,a2)
func(1,2,4,5,a2=9)  #a1=1  args=(2, 4, 5),a2=9

def func(a1,*args,a2=9): #args后面还有参数时,a2必须要用关键字传参
    print(a1,args,a2)
func(1,2,4,5)  #a1=1  args=(2, 4, 5),a2=9

def func(**kwargs):  位置传参
    print(kwargs)
func(k1=1) #{'k1': 1}
func(k1=1,k2='alex')  #{'k1': 1, 'k2': 'alex'}

5.3.5 常见定义函数

调用函数顺序:位置参数>关键字参数,位置参数先

def func(a1,a2):
    pass
   
def func(a1,a2=None):
    pass
    
def func(*args,**kwarge):
    pass

5.3.6 作用域

python中:

  1. py文件:全局作用域

  2. 函数:局部作用域

  3. 一个函数是一个作用域

nt(x1)
    print(a)#1
    print(b) #2

b = 2
print(a)#1
s1()#666
print(x1)#报错


def s2():
    print(a,b)#1,2
    print(x1)#可以找到函数位置

s2()
'''

a = 1
def s1():
    x1 = 666
    print(x1)
    print(a)#1
    print(b)#2
    def xxx():
        pass

b = 2
print(a)#1
s1()#666
print(x1)#报错

a=888
def s2():
    print(a,b)#888,2

    s1()#666
s2() # 888 2
def func():
    x = 9
    print(x)
func()#9

def func():
   x = 9

作用域中查找数据的规则:优先在自己的作用域查找数据,自己没有就去“父级”-->"父级“-->全局,全局没有就报错

全局变量必须大写,局部变量小写

例题:

##自己有
x =10
def func():
    x = 9
    print(x)
func() #9

##自己没有,父级有
x =10
def func():
    print(x)
func() #10

##自己没有,全局也没有
def func():   
    print(x)
func()#报错

def func():
    x = 9
    print(x)#9
    def x1():
        x =999
        print(x)
    print(x)
func()#9
'''
'''
x =10
def func():
    x = 9
    print(x)#9
    def x1():
        x =999
        print(x)
    print(x)#9
    x1()#999
func()#9
'''
x =10
def func():
    x = 8
    print(x)#8
    def x1():
        x =999
        print(x)

    x1()#999
    print(x)  
func()# 8


x =10
def func():
    x = 8
    print(x)#8
    def x1():
        print(x)
    x = 9 
    x1()#9
    x = 11
    print(x)
func()#11

x =10
def func():
    x = 8
    print(x)#8
    def x1():
        print(x) 
 
    x1() #8
    x = 9
    x1() #9
    x = 10
    print(x)
func()#10

练习题:子作用域中只能找到父级中的值,默认无法重新为父级赋值(global/nonlocal可以强制做)

name = 'oldboy'
def func():
    name = 'alex'  #在自己作用域再创建一个这样的值
    print(name) #alex 
func()  
print(name) ##oldboy
########

name = [1,2,3,4]
def func():
    name .append(999) 
    print(name)#[1, 2, 3, 4, 999]
func()  
print(name) #[1, 2, 3, 4, 999]
##注意:因为字符串是不可变类型,而列表、元组等是可变类型所以可以用增加的方法


####如果非要对全局的变量进行赋值可以用global进行重新修改
name = '老男孩'
def func():
    global name
    name = 'alex'

func()  
print(name) #alex
######示例
name = '老男孩'
def func():
    name = 'alex'
    def inner():
        global name
        name = 999
    inner()
    print(name)  #alex
func()
print(name) #999

###nonlacal,找到父级的变量修改
name = '老男孩'
def func():
    name = 'alex'
    def inner():
        nonlocal name  #nonlocal 是指找到上一级的name修改
        name = 999
    inner()
    print(name) #999

func()
print(name)  #老男孩
######示例
name = '老男孩'
def func():
    name = 'alex'
    def inner():
        name = 999
        def test():
            global name
            name = '888'
        test()
    inner()
    print(name) #alex
func()
print(name)  #888
####示例
name = '老男孩'
def func():
    name = 'alex'
    def inner():
        name = 999
        def test():
            nonlocal name
            name = '888'
        test()
    inner()#888
    print(name) #alex
func()
print(name)  #老男孩

5.4 函数的小高级

1.函数也可以认为是一个数据

2.函数内部的数据会不会混乱?

  1. 函数内部执行相互之间不会混乱

  2. 内存的数据销毁的情况:函数执行完,内部的元素无人使用

5.4.1 函数名可以当作变量使用

def func():
    print(123)
v1 = func
func()#123
v1() #123  
def func():
    print(123)

func_list = [func,func,func]
for item in func_list:
    v = item()
    print(v)  # 123 none 123 none 123 none 先执行函数,在返回值
def func():  #函数一般不当字典的key
    print(123)
def bar():
    print(666)
info = {'k1':func,'k2':bar}
info['k1']() #123
info['k2']()#123

混淆题:

def func():
    print(123)
func_list1 = [func(),func(),func()]  #有返回值
func_list2 = [func,func,func]
print(func_list2)
print(func_list1)
'''

def func():
    return 12
info = {
    'k1':func,
    'k2':func()
}
print(info)  #{'k1': <function func at 0x00000000028F4C18>, 'k2': 12}

5.4.2 函数可以当做参数进行传递

原则:谁调用的函数,返回值就给谁

def func(arg):
    arg()
def show():
    print(666)
func(show)  #666

def func(arg):
    v1 = arg()
    print(v1) #none
def show():
    print(666)  #执行完了没有返回值 所以是none
func(show)  #666
def func(arg):
    print(arg)
func(1) #1

def show():
    return 999
func(show)  #打印show函数所在的内存地址
func(show()) # 999
def func(arg):
    v1 = arg()
    print(v1) #none show的返回值是v1,所以v1是none
def show():
    print(666)
result = func(show)  #666
print(result)  #none  谁调用的函数,返回值就给谁
#先计算func(show),所以先print666,因为func调用的是show函数,所以v1等于它的返回值none,
# 然后在计算result,因为result调用的是func函数,所以result的结果是func的返回值none
面试题
def func():
    print('话费查询')
def bar():
    print('宽带办理')
def show():
    print('流量查询')
def text():
    print('人工服务')
def base():
    print('流量包办理')
info = {
    'f1':func,
    'f2':bar,
    'f3':show,
    'f4':text,
    'f5':base,
}
choice = input('请选择你要的服务:')
function_name = info.get(choice)
if function_name:
    function_name()
else:
    print('输入错误')

5.4.3 lambda表达式

用于表示简单的函数

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
   
   func = lambda a1,a2: a1+a2
func1 = lambda : 100   #没有参数,返回100
func2 = lambda x1 : x1 *10

func3 = lambda *args,**kwargs: len(args) +len(kwargs)
v1 = func3(1,2,33)
print(v1) #3

DATA = 100
func4 = lambda a1: a1 + 100
v1 = func4(1)
print(v1) #101

DATA = 100
def func():
    DATA = 1000
    func4 = lambda a1: a1 + DATA
    v1 = func4(1)
    print(v1)
func() #1001

func5 = lambda n1,n2: n1 if n1 > n2 else n2
v= func5(1,2)
print(v)#2

练习题:

USER_LIST = []
func1 = lambda x: USER_LIST.append(x)  #这行的返回值是none
v1 = func1('alex')
print(v1)  #None
print(USER_LIST)  #['alex']
'''

#看是否有返回值,是看执行完这个之后是否返回东西,列表几乎所有的功能基本上返回值都是none,对于字符串所以的方法返回的都是一个新的返回值
def func(x):
    v = x.strip()
    return v
result = func('  alxe  ')
print(result)  #alex

func1 = lambda x:  v = x.split('l')   
v1 = func1('alex')
print(v1t)  #[a,lex]

func_list = [lambda x: x.strip(),lambda y:y+199,lambda x,y:x+y]
v1 = func_list[0](' alex ')
print(v1)
v2 = func_list[1](100)
print(v2)
v3 = func_list[2](1,2)

5.4.4内置函数

  1. 自定义函数

  2. 内置函数

    1. len

    2. open

    3. range

    4. id

    5. type

    6. 输入输出:print、input

    7. 强制转换

      1. dict()

      2. list()

      3. int()

      4. str()

      5. bool()

      6. set()

    8. 数学相关

      1. abs,绝对值

      2. float 转换成浮点型(小数)
      3. max 找到最大值
      4. sum 求和
      5. divmod,两个数相除得商和余数
    9. 与进制相关
      1. bin ,只能是十进制转换成二进制 
      2. oct,十进制转换成八进
      3. int,将其他进制转换成十进制
      4. hex,将十进制转换成十六进制
    10. 编码相关
      1.  chr:将十进制数字转换成unicode编码中的对应字符串
      2. ord:将Unicode编码中的字符串转换成对应的十进制数字 
      3. 应用:
        随机验证码
        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)
        import random#导入一个模块
        v= random.randint(起始,终止) #得到一个随机数

 面试题

1字节= 8位 0101的位置
IP:192,168,12,79-->四个字节通过点连接起来的,地址的范围是0-255
把IP = '192,168,12,79'中的每个十进制数转换成二进制并通过逗号连接起来生成一个心的字符串

IP = '192,168,12,79'
ip_list = IP.split(',')
# print(ip_list)  ['192', '168', '12', '79']
result = []
for item in ip_list:
    result.append(bin(int(item)))
print(','.join(result)) 
#0b11000000,0b10101000,0b1100,0b1001111

##面试题
请将IP = '192,168,12,79'中的每个十进制数转换成二进制,把二进制拼接起来并转换成十进制
ip = '10.3.9.12'
ip_list = ip.split('.')
print(ip_list)
result = []
for item in ip_list:
    result.append(bin(int(item)).replace('0b','').rjust(8,'0'))
    # print(result)
    data = int(''.join(result),base=2)
print(data)

# ip = '10.3.9.12'
# print(int(''.join(bin(int(i))[2:].rjust(8,'0') for i in ip.split('.')),base=2))
'''
def ip(ip_add):
    ip_list = list()
    for i in ip_add.split('.'): #把地址用. 分割开
        ip_list.append(bin(int(i)).replace('0b', '').rjust(8, '0'))
                    #bin(int(i))是把每一个十进制的ip转换成二进制,replace('0b', '')把二进制中0b的位置替换成空,
        # .rjust(8,'0')是指前面替换成空的位置用八个零填充   .rjust(width, 'fillchar')

    return int(''.join(ip_list), base=2)
ip_add = input('输入一个IP地址:')
print(ip(ip_add))

高级一点的内置函数

a:map,循环第二个参数的每个元素,然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到列表中并返回

map是有返回值的不影响v1
v1 = [11,22,33,44]
#第一个参数必须是一个函数
#第二个参数必须是可迭代的类型,可被for循环的(列表,字符串,字典,元组,集合),map会循环一个函数
def func(arg):
    print(arg)
result = map(func,v1)  #每循环一次会把函数的返回值添加到一个空列表中[none,none,none,none]
print(list(result))  #

v1 = [11,22,33,44]
def func(arg):
    return arg + 100
result = map(func, v1)  # 每循环一次会把函数的返回值添加到一个空列表中[none,none,none,none]
print(list(result))  # [111, 122, 133, 144]
'''
v1 = [11,22,33,44]
result = map(lambda x:x+100,v1)
print(result)  #[111, 122, 133, 144]
print(list(result)) #特殊对象

b:filter(过滤出想要的)

 

v1 = [11,22,33,44]
result = map(lambda x:x+100,v1)
print(result)  #[111, 122, 133, 144]
print(list(result)) #特殊对象
'''

v1 = [11,22,33,'ade',44,'xf'] #找到列表中的数字
def func(x):
    if type(x) == int:
        return True
    return False
            
result = filter(func,v1)
print(list(result))  #[11, 22, 33, 44]

v1 = [11, 22, 33, 'ade', 44, 'xf']  # 找到列表中的数字
def func(x):
    # return True if type(x) ==int else False
    return type(x) ==int

result = filter(func, v1)
print(list(result))  # [11, 22, 33, 44]

v1 = [11, 22, 33, 'ade', 44, 'xf']  # 找到列表中的数字
def func(x):
result = filter(lambda x:type(x)==int,v1)
print(list(result))  # [11, 22, 33, 44]

c:reduce(乘,除,加,减,得到一个数)

import functools

v1 = [1,2,3,4,5]
def func(x,y):
    return x+y  #第一次返回是什么,在下一次执行的时候第一个数就是第一次返回的值
result = functools.reduce(func,v1)
print(result)  #15

result = functools.reduce(lambda x,y:x+y,v1)
print(result)

5.5 函数中高级

5.5.1函数可以当作返回值

def func():
    print(123)
 def bar():
     return func
 v = bar()  
 v()#none
def bar():
    def inner():
        print(123)
    return inner
v = bar()
v() #123 v是inner
name = 'oldboy'
def bar():
    name = 'alex'
    def inner():
        print(name)
    return inner
v = bar()
v() #alex

5.5.2 闭包的概念

闭包的概念:在函数中的一定区域创建数据并为其维护自己的数据,为了以后执行是方便调用(应用场景:装饰器、SQLAlchemy源码)

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

函数执行的流程分析(函数在何时是由谁创建的,作用域就从这边开始找)

练习题

name = 'alex'
def base():
    print(name)
def func():
    name = 'eric'
    base() #调用了base
func() #alex

name = 'alex'
def func():
    name = 'eric'
    def base():
        print(name)
    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)
    #item = 9
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

5.6装饰器

  1. 指的是在不改变原来函数内部代码的基础上,可以在函数执行是在之前或者之后执行某个功能

  2. 应用场景:想要为函数扩张功能时,可以选择用装饰器

  3. 装饰器的编写格式:

    def 外层函数(函数名):
        def 内层函数(*args,**kwargs):#表示函数可以接收任意参数
            return 函数名
        return 内层函数
            

5.6.1装饰器应用格式

@外层函数
def index():
    pass
 index()
示例:
#装饰器的编写
def x(func):  #func表示被装饰的函数
    def y():
        ret = func()
        return ret
    return y
@x  #@的作用是执行x函数,把下面index函数当做参数
x(index)
#第二步:将func的返回值重新赋值给下面的函数名,index = x(index)
def index():
    pass
@x
def mange():
    pass
#执行函数,自动触发装饰器
index()
def func():
    pass
v = 10
v = func

def base():
    print(1)
def bar():
    print(2)
bar = base
bar() #1
def func(arg):
    def inner():
        arg()
    return inner
def f1():
    print(123)
v1 = func(f1)
v1() #123
def func(arg):
    def inner():
        arg()  #=f1
    return inner
def f1():
    print(123)
    return 666
v1 = func(f1)
result = v1() #执行inner函数 inner返回none/执行f1函数打印了123,return666没有人接收
print(result)  #123  None
'''
def func(arg):
    def inner():
        return arg()  #=f1
    return inner
def f1():
    print(123)
    return 666
v1 = func(f1)
result = v1() #执行inner函数 inner返回none/执行f1函数打印了123,return 666被接收了
print(result)  #123  666
def func(arg):
    def inner():
        v = arg()
        return v
    return inner
#第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
#第二步:将func的返回值重新赋值给下面的函数名,index = func(index)
@func
def index():
    print(123)
    return 666
print(index) #<function func.<locals>.inner at 0x00000000028AC168>
import time
def wrapper(func):
    def inner():
        star_time = time.time()
        v = func()
        end_time = time.time()
        print(end_time - star_time)
        return v
    return inner
@wrapper
def func1():
    time.sleep(2)
    print(123)

def func2():
    time.sleep(1)
    print(123)

def func3():
    time.sleep(1.5)
    print(123)
func1()

问题:为什么加*args,**kwargs?可以接收很多的参数

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

def index():
    print(123)
index() #123

def show(a1):
    print(a1+100)
show(1)  #101

5.6.2 关于参数

def x(func):
    def inner(a1):
        return func(a1)
    return inner
@x
deef index(a1):
    pass
对于有一个参数的,装饰器中inner和func都有一个参数
def x(func):
    def inner(a1,a2):
        return func(a1,a2)
    return inner
@x
deef index(a1,a2):
    pass
#index = inner
index(1,2)
对于有两个个参数的,装饰器中inner和func都有两个参数
让参数统一的目的是为了给原来的index传参

给好几个函数写一个统一的装饰器

def wrapper(func):
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

@wrapper
def f1():
    pass
@wrapper
def f2(a1):
    pass
@wrapper
def f3(a1,a2):
    pass

5.6.3 关于返回值

执行谁的参数返回值就是谁的

def wrapper(func):
    def inner(*args,**kwargs):
        data = func(*args,**kwargs)
        return data
    return inner

@wrapper
def f1():
    print(123)
 #func = f1函数
inner =f1函数
执行f1函数,f1函数的返回值是none
v1 = f1() #NOne
def wrapper(func):
    def inner(*args,**kwargs):
        data = func(*args,**kwargs)
        return 666
    return inner

@wrapper
def f1():
    print(123)
 #func = f1函数
inner =f1函数
v1 = f1() #
def wrapper(func):
    def inner(*args,**kwargs):
        data = func(*args,**kwargs)  #666 data执行的是原来的f1函数,它的返回值是666
    return inner

@wrapper
def f1():
    print(123)
    return 666

v1 = f1() #none  inner没有返回值

装饰器建议的写法:

def wrapper(func):
    def inner(*args,**kwargs):
        data = func(*args,**kwargs)
        return 666
    return inner

5.6.4关于前后

def wrapper(func):
    def inner(*args,**kwargs):
        print('调用函数之前')
        data = func(*args,**kwargs) #执行原函数并获取返回值
        print('调用函数之后')
        return data
    return inner

@wrapper
def f1():
    print(123)
    return 666
f1()

5请为以下所有函数编写一个装饰器,添加上装饰器后可以实现:
# 将被装饰的函数执行5次,讲每次执行函数的结果按照顺序放到列表中,最终返回列表。
'''
import random
def wrapper(f):
    def inner(*args,**kwargs):
        value =[]
        for i in range(5):  #循环执行原函数
            data = f(*args,**kwargs)  #执行原函数
            value.append(data)
        return value
    return inner

@wrapper
def func():
    return random.randint(1,4)

reuslt = func() # 执行5次,并将每次执行的结果追加到列表最终返回给result
print(reuslt)

5.6.5 带参数的装饰器

#第一步:执行ret = xxx(index)
#第二步:将返回值赋值给index = ret

@xxx
def index():
    pass

#第一步:执行v1 = xxx(9)
#第二步:执行ret = v1(index)
#第三步:index = ret

@xxx(9)
def index():
    pass

练习题

#写一个带参数的装饰器,实现:参数是多少,被装饰的函数就执行多少次并把每次的结果返回一个列表
def xxx(arg):
    def wrapper(func):
        def inner(*args, **kwargs):
            value = []
            for i in range(arg):
                data = func(*args, **kwargs)
                value.append(data)
            return value
        return inner
    return wrapper

#先执行xxx(5)得到返回值wrapper,在通过wrapper = index执行代码,把返回值赋值给index
@xxx(5)
def index():
    pass

v = index()
print(v)  #[None, None, None, None, None]

#写一个带参数的装饰器,实现:参数是多少,被装饰的函数就执行多少次并把最后一次的的结果返回
def xxx(arg):
    def wrapper(func):
        def inner(*args, **kwargs):
                data = func(*args, **kwargs)
            return data
        return inner
    return wrapper

#先执行xxx(5)得到返回值wrapper,在通过wrapper = index执行代码,把返回值赋值给index
@xxx(5)
def index():
    pass

v = index()
print(v)  #[None]

#写一个带参数的装饰器,实现:参数是多少,被装饰的函数就执行多少次并返回执行结果中最大的值
def xxx(arg):
    def wrapper(func):
        def inner(*args, **kwargs):
            value= 0
            for i in range(arg):
                data = func(*args, **kwargs)
                if data >value:
                    value = data
            return value
        return inner
    return wrapper

#先执行xxx(5)得到返回值wrapper,在通过wrapper = index执行代码,把返回值赋值给index
@xxx(5)
def index():
    pass

v = index()
print(v)  #[None]
990个执行一个函数,另外10个执行一个函数

def xxx(arg):
    def wrapper(func):
        def inner(*args, **kwargs):
            if arg:
                return 123
            return func(*args, **kwargs)

        return inner
    return wrapper
@xxx(True)
def index990():
    pass
@xxx(False)
def index10():
    pass

5.7推导式

5.7.1 列表推导式

基本格式

'''
目的:方便生成一个列表
格式:
   v1 = [i for i in 可迭代对象]
   v2 = [i for i in 可迭代对象 if 条件] #先做循环,为true时才append进去

'''

vals = [i for i in 'alex']
print(vals) #['a', 'l', 'e', 'x']

格式:
变量 = [for循环的变量 for循环一个可迭代对象]
v2 = [i+100 for i in range(10)]
v3 = [99 if i >99 else 66 for i in range(10)]  #[66, 66, 66, 66, 66, 66, 99, 99, 99, 99]

def func():
    pass
v4 = [func for i in range(10)] #10个func

v5 = [lambda : 100 for i in range(10)]
result = v5[9]() #100

#新浪微博面试题
v6 = [lambda x: x*i for i in range(10)]
v6是什么?是函数
v6[0](2)#18
##面试题
def num():
    return[lambda x:i*x for i in range(4)]
#num()-->[函数,函数,函数,函数] i=3
x = 2
print([m(2) for m in num() ]) #[6,6,6,6]

#####筛选
v7 = [i for i in range(10) if i>5] #先做循环,true才append进去
print(v7)  #[6,7,8,9]

5.7.2 集合推导式 会自动去重

vals = {i for i in 'alex'}

5.7.3 字典推导式

v1 = {'k'+str(i):i for i in range(10)}
print(v1)#{'k0': 0, 'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4, 'k5': 5, 'k6': 6, 'k7': 7, 'k8': 8, 'k9': 9}

5.8 递归

递归是自己调用自己,一直反复下去。(效率比较低)

默认递归限制的最大次数是1000(官网上有写)在sys里面有个模块可以调用能告诉我们递归的最大次数,可以修改但是不建议修改

def func():
    print(1)
    func()
    
 func()
def func(i):
    print(1)
    func(i+1)
    
 func(1)#1,2,3,4,5....循环下去
def func(a,b):
    #1
    #1
    #2
    #3
    #5
    print(b) #1 #1
    func(b,a+b) #1 1  #1 2
func(0,1)
有无返回值的区别

def func(a):
    if a == 5:
        return 1000 
    result = func(a+1) + 10
    return result
v = func(1) #1040

def func(a):
    if a == 5:
        return 1000 
    result = func(a+1) + 10
    
v = func(1) #None

 

     

posted @ 2020-03-19 21:48  炜琴清  阅读(203)  评论(0编辑  收藏  举报