zoukankan      html  css  js  c++  java
  • 第五章函数

    第五章 函数

    5.1 函数的本质及应用场景

    截至目前:面向过程编程(可读性差/可重用性差)

    对于函数编程:

    1. 本质:将N行代码拿到别处并给他起一个名字,以后通过名字就可以找到这段代码并执行
    2. 应用场景:
      • 代码重复执行
      • 代码特别多超过一屏,可以选择通过函数进行代码的分割
    # 面向过程编程 
    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()
    

    5.2 函数定义

    5.2.1 基本定义函数

    1. 基本形式

      def 函数名():       #函数的定义
          代码            #函数内容
          
      函数名()            #函数的执行
      
    2. 注意

      • 函数如果不被调用,则内部代码永远不会被执行
      • len(计算长度)是python内部写好的一个函数

    5.2.2 参数(个数不限制)

    5.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')
      

    5.2.2.2 位置传参

    • 传参:调用函数并传入参数
    • 要求:严格按照位置进行传参
    • 位置参数:positional argument
    • 基本形式
    def func(a,b):
        print(a,b)
        
    func(11,22)               #位置都是一一对应的,a = 11,b = 22
    

    5.2.2.3 关键字传参

    • 关键字参数:keyword argument

    • 基本形式

      def func(a,b):
          print(a,b)
          
      func(b = 11,a = 22)        #按照关键字进行传参,可以交换位置
      
    • 注意:open(打开文件)是python内部写好的一个函数,运用的就是关键字传参

    • 关键字传参和位置传参可以混合使用

      • 位置参数必须在关键字参数的前面
      • 位置参数的个数 + 关键字参数的个数 = 总参数个数
      • 一个参数不能传多次

    5.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)
      
      # [1,3]   [11,22,2]   [1,3] #注意这里是最后打印的l1,l3,公用的同一个内存地址都是[1,3]。
      print(l1,l2,l3)
      
      ##################
      def func(a,b=[]):
          b.append(a)
          print(b)
      
      l1 = func(1)
      l2 = func(2,[11,22])
      l3 = func(3)
      
      # [1]   [11,22,2]   [1,3] #注意这里是立即打印的
      print(l1,l2,l3)
      
      

    5.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'} 
    
    
    1. 参数相关重点

      • 定义函数

        #情况一:
        def func(a,b):
            pass
        
        #情况二:
        def func(a,b = None):
            pass
        
        #情况三:
        def func(*args,**kwargs):
            pass
        
        
      • 调用函数:位置参数 > 关键字参数

    2. 练习题

    # 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')
    
    

    5.2.3 返回值(return)

    1. 作用
      • 返回值
      • 终止函数的执行
    2. 基本形式
    def func(arg):
    	代码             #函数内容
    	return 9         #返回值为9,默认:return None
    
    val = func('ads')    #设置一个变量接收返回值
    print(val) #9
    #特殊情况:
    def func():
    	return 2,3,'alex'     #返回是一个元组
    
    val = func()
    print(val)                #(2,3,'alex')
    
    1. 返回值相关重点
      • 函数没有返回值,默认返回: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)
    
    1. 数据类型中的方法有没有返回值

      • 无返回值

        #示例:
        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,返回字典所有的键值对

    5.2.4 总结

    1. 函数的基本结构:
    #情况一
    def f1():
        函数内容
    f1()
    
    #情况二
    def f2(a):
        函数内容    
    f2(1)
    
    #情况三
    def f3():
        函数内容
        return 
    v1 = f3()
    
    #情况四
    def f4(a1,a2):
        函数内容
        return a1+a2
    v2 = f4(1,7)
    
    
    1. 函数内部的数据是否会混乱?
      • 函数内部执行相互之间不会混乱
      • 执行完毕 + 内部元素不被其他人使用 => 销毁

    5.3 函数小高级

    5.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)
    
    

    5.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('输入错误')
    
    

    5.3.3 函数可以当做字典的value

    def fun1():
        pass
    def fun2():
        pass
    def fun3():
        pass
    def fun4():
        pass
    info = {
    
        'f1':fun1,
        'f2':fun2,
        'f3':fun3,
        'f4':fun4,
    
    }
    
    choice = input('<<')
    func_name = info.get(choice)
    
    if func_name: #如果有key
        func_name()
    
    else:
        print('...')
    

    5.3.4 匿名函数: lambda表达式

    1. 作用:用于表达简单的函数

    2. 基本形式:

      #三元运算,为了解决简单的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
      
      
    3. 重点:

      • lambda表达式只能用一行表示函数
      • 用lambda表达式表示函数时,无法设置新变量,只能用参数作变量
      • 列表所有方法基本上都是返回None,字符串的所有方法基本上都是返回新值
    4. 练习题

      # 练习题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
      
      

    5.4 函数中高级

    5.4.1 函数可以做返回值

    #示例:
    def func():
        print(123)
    def bar():
        return func
    
    v = bar()
    v()
    
    

    5.4.2 闭包

    1. 概念:为函数创建一块区域并为其维护自己数据,以后执行方便调用
    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()
    v2()
    
    #区分:
    # 不是闭包  没有使用name
    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() 
        
    # 第二题
    name = 'alex'
    def func():
     	name = 'eric'
        def base():
        	print(name)
        base()
    func()
    
    # 第三题
    name = 'alex'
    def func():
     	name = 'eric'
        def base():
        	print(name)
        return base 
    base = func()
    base()
    
    #注意:函数在何时被谁创建?
    #示例:
    info = []
    def func():
        print(item)   
    for item in range(10):
        info.append(func)
    
    info[0]()
    
    
    #面试题
    info = []
    def func(i):
        def inner():
            print(i)
    	return inner
    for item in range(10):
        info.append(func(item))
    
    info[0]()
    info[1]()
    info[4]()
    
    

    5.4.3 高阶函数

    1. 把函数当作参数传递
    2. 把函数当作返回值
    3. 注意:对函数进行赋值

    5.5 内置函数

    函数分为自定义函数和内置函数

    python内置函数分类:

    5.5.1 强制转换

    • int() / str() / bool() / list() / tuple() / dict() / set()

    5.5.2 输入输出

    • input() / print()

    5.5.3 数学相关

    • abs():计算绝对值

    • sum():求和

    • float():转化为浮点型(小数)

      v = 55
      v1 = float(55)
      print(v1)        #55.0
      
      
      • 补充:int(55.5) #只保留整数:55
    • max():找到最大值

    • min():找到最小值

    • divmod():取两数相除的商和余数

      #示例:
      a,b = divmod(1001,5)
      print(a,b)          ##a=200,b=1
      
      
      
      • 注意:divmod在分页展示时用得比较多

        # 练习题  请通过分页对数据进行展示
        """
        要求:
            每页显示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  四舍五入
      

    5.5.4 进制转换相关

    • bin():将十进制转换成二进制

    • oct():将十进制转换成八进制

    • int():将其他进制转换成十进制 #八进制和18进制之间不能直接转换,可以先转成10进制在进行转换

      • 默认: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():将十进制转换成十六进制

    #1字节等于8位
    # IP: 192.168.12.79  ->  001010010 . 001010010 . 001010010 . 001010010
    
    # 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。
    ip = "192.168.12.79"
    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)
    
    

    5.5.5 编码相关

    • chr():将十进制数字转换成 unicode 编码中的对应字符串 (unicode包括ascci)

    • ord():根据字符在 unicode 编码中找到其对应的十进制

      #应用:生成随机验证码
      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)
      
      

    5.5.6 内置函数高级

    • map(函数,可迭代对象):一起执行

      • 循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回
      #示例:
      v1 = [11,22,33,44]	
      result = map(lambda x:x+100,v1)
      print(list(result))  #python3中为节省内容要强制转换下list
      
      
    • 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))
      
      # 用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))
      
      
    • map / filter(python2与python3的区别九)

      • python2:返回列表,直接创建值,可以通过索引取值
      • python3:返回迭代器,不直接创建值,通过循环,边循环边创建
    • reduce(函数,可迭代对象):得到结果

      import functools
      v1 = ['wo','hao','e']
      def func(x,y):
          return x+y
      result = functools.reduce(func,v1) 
      print(result)
      
      # 用lambda表达式:
      result = functools.reduce(lambda x,y:x+y,v1)
      print(result)
      
      

    5.5.7 类相关

    • type():查看数据类型

      class Foo:
          pass
      
      obj = Foo()
      if type(obj) == Foo:
          print('obj是Foo类的对象')
      
      
    • issubclass(类,类或其基类):判断前一个类是否是后一个类或其基类的子类

      • 结果是布尔类型,是 -> True,否 -> False
      class Base:
          pass
      
      class Base1(Base):
          pass
      
      class Foo(Base1):
          pass
      
      class Bar:
          pass
      
      print(issubclass(Bar,Base))
      print(issubclass(Foo,Base))
      
      
    • isinstance(对象,类或其基类):判断一个对象是否是一个类或其基类的实例(对象)

      • 结果是布尔类型,是 -> True,否 -> False
      • 注意:判断一个对象是否是一个类的实例(对象),一定要用type,不要用isinstance
      class Base(object):
          pass
      
      class Foo(Base):
          pass
      
      obj = Foo()
      print(isinstance(obj,Foo))  # 判断obj是否是Foo类或其基类的实例(对象)
      print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象)
      
      
    • super().方法名():根据self对象所属的类的继承关系,按照顺序依次找方法并执行(找到第一个为止)

      class Base(object):
          def func(self):
              super().func()  # 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个为止)
              print('base.func')
      
      class Bar(object):
          def func(self):
              print('bar.func')
      
      class Foo(Base,Bar): # Foo -> Base -> Bar
          pass
      
      obj = Foo()
      obj.func()
      
      

    5.5.8 其他

    • len() :计算长度
    • open() :打开文件
    • range()
    • id() :查看内存地址

    5.7 作用域

    5.7.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)
      
      

    5.7.2 递归

    • 函数自己调用自己。(效率低)

      def func():
          print(1)
          func()
          
      func()
      
      
      # 递归的返回值
      def func(a):
          if a == 5:
              return 100000
          result = func(a+1) + 10
      v = func(1)   #此时只有a=5的时候会有返回值
      
      name = 'alex'
      def func():
          def inner():
              print(name)
           return inner
      v =func()
      

    5.7.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"
        
        

    5.8 推导式

    5.8.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 是什么? 列表中9个函数名
    # 2.请问 v7[0](2) 的结果是什么? 18
    
    # 面试题
    def num():
        return [lambda x:i*x for i in range(4)] #lambda 就是一个函数,不被调用,内部代码不会执行
    # num() -> [函数,函数,函数,函数]
    print([ m(2) for m in num() ]) # [6,6,6,6]  
    
    

    5.8.2 集合推导式

    # 目的:方便的生成一个集合
    # 格式:
    v1 = { i for i in 'alex' }
    
    

    5.8.3 字典推导式

    # 目的:方便的生成一个字典
    # 格式:
    v1 = { 'k'+str(i):i for i in range(10)}
    
    

    5.8.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)) 的区别?
    
    

    5.9 装饰器

    5.8.1 目的

    • 在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能

    5.8.2 应用场景

    • 想要为函数扩展功能时,可以选择用装饰器

    5.8.3 基本装饰器

    1. 基本格式:

      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)
      
      
    2. 总结

      • 编写格式:
      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   #这里的返回值 就是装饰器里的ret 接受的返回值
      
      # 执行函数,自动触发装饰器了
      v = index()
      print(v)	
      
    3. 示例:

      def func(arg):
          def inner():
              print('before')
              v = arg()
              print('after')
              return v 
          return inner 
      
      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()
      

    5.8.4 装饰器建议的写法

    def wrapper(f):
        def inner(*args,**kwargs):
            data = f(*args,**kwargs)
            return data   #此时返回的是原函数的666
        return inner
    
    @wrapper
    def func():
        print('123')
        return 666
    ret = func()  #这里接受666
    print(ret)
    #123
    #666
    

    5.8.5 带参数的装饰器

    1. 应用场景:flask框架 / django缓存 / 写装饰器实现被装饰的函数要执行N次

      # 第一步:执行 ret = xxx(index)
      # 第二步:将返回值赋值给 index = ret 
      @xxx
      def index():
          pass
      
       
      # 第一步:执行 v1 = uuu(9)
      # 第二步:ret = v1(index)
      # 第三步:index = ret 
      @uuu(9)    相当于先执行函数unn()
      def index():
          pass
      
      
    2. 区别:

      # 普通装饰器
      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
      
      
    3. 练习题

      # 习题一:
      # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。
      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)
      

    5.10 迭代器

    5.10.1 基本知识

    1. 用途:对 某种对象(str/list/tuple/dict/set类创建的对象-可迭代对象)中的元素进行逐一获取

    2. 表象:具有__next__方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)

    3. 示例:

      • 列表转换成迭代器:
        • v1 = iter([11,22,33,44])
        • v1 = [11,22,33,44].__iter__()
      • 迭代器想要获取每个值:反复调用 val = v1.__next__()
      v1 = [11,22,33,44]
      
      # 列表转换成迭代器
      v2 = iter(v1)
      
      # 迭代器获取每个值
      result1 = v2.__next__()
      print(result1)
      result2 = v2.__next__()
      print(result2)
      result3 = v2.__next__()
      print(result3)
      result4 = v2.__next__()
      print(result4)
      
      result5 = v2.__next__()
      print(result5)    # 报错:Stoplteration    表示已经迭代结束
      
      
    4. for循环:运用了迭代器

      v1 = [11,22,33,44]
      
      # 1.内部会将v1转换成迭代器
      # 2.内部反复执行 迭代器.__next__()
      # 3.取完不报错
      for item in v1:
          print(item)
      
      

    5.10.2 可迭代对象

    1. 表象:可以被for循环,内部有__iter__方法的对象就可以称为是可迭代对象。

    2. 如何让一个对象变成可迭代对象?

      • 在类中实现__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()
      
    3. 注意:只要能被for循环,就是去看他内部的__iter__方法

    5.11 生成器

    5.11.1 基本知识

    1. 可以理解为:函数的变异、特殊的迭代器、特殊的可迭代对象

    2. 生成器的作用:

      • 生成数据
      • 迭代
    3. 示例:

      # 生成器函数(内部是否包含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)
      

    5.11.2 关键字

    1. yield

      • 用途:判断函数是否是生成器函数
    2. 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
      

    5.11.3 总结

    1. 重点:

      • 函数中如果存在yield,那么该函数就是一个生成器函数
      • 调用生成器函数会返回一个生成器
      • 生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值
    2. 建议:

      • 生成器函数中一般不要有return

      • 如果需要终止生成器函数中的循环,可以用return

        def func():
            count = 1
            while True:
                yield count
                count += 1
                if count == 100:
                    return
        val = func()
        for item in val:
            print(item)
        
    3. 生成器示例:读取大文件内容

      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)
      

    5.12 总结

    • 迭代器,对可迭代对象中的元素进行逐一获取,迭代器对象的内部有一个next放法。用于一个个的获取数据

    • 可迭代对象,可以被for循环,且此类对象中都有iter方法且要返回一个迭代器(或生成器都可以)

    • 生成器,函数内部有yiled则就是生成器函数,调用函数则返回一个生成器,循环生成器时,函数内部代码才会执行

      生成器即有iter方法,也有next方法,所以说生成器是特殊的可迭代对象和特殊的迭代器

  • 相关阅读:
    Car HDU
    Defeat the Enemy UVALive
    Alice and Bob HDU
    Gone Fishing POJ
    Radar Installation POJ
    Supermarket POJ
    Moo Volume POJ
    Text Document Analysis CodeForces
    checkbox全选与反选

  • 原文地址:https://www.cnblogs.com/hanfe1/p/11511116.html
Copyright © 2011-2022 走看看