zoukankan      html  css  js  c++  java
  • python3-基础6

    函数嵌套调用: 再调用一个函数的过程中,又调用了其他的函数

    函数的嵌套定义:在一个函数的内部,又定义另外一个函数,函数内部定义的变量,在外部不能被调用

    名称空间:一种隔离的概念,专门用来存放名字的地方,准确的说是存放名字与变量值绑定关系的地方,一个内存空间与另一个内存空间完全隔离

    python中,有哪些名称空间,名称空间和函数没毛关系

      内置名称空间:python自带的名字,在python解释器启动时产生,存放一些python内置的名字

      全局名称空间:再执行文件时,存放文件级别定义的名字,没有缩进定义的名字,就是全局的名字

      局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间,用来存放该函数内定义的名字

                          该名字在函数调用时生效,在函数调用结束后失效。也就是函数内定义的名字。

     优先掌握

     加载顺序: 内置---》全局---》局部

     取值顺序: 局部---》全局---》内置      (参照点为局部)  ,需要注意的是:在全局无法查看局部的,在局部可以查看全局的,

    1、作用域即范围
           - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效  globals()
        - 局部范围(局部名称空间属于该范围):临时存活,局部有效  locals()
    2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,

    global  在局部位置修改全局参数

    nonlocal    只在局部生效,在局部位置修改上层参数

    优先掌握: 作用域关系,在函数定义时就已经固定,与调用位置无关

          再调用函数时,必须必须回到函数原来定义的位置去找作用域关系。

    LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
    locals 是函数内的名字空间,包括局部变量和形参
    enclosing 外部嵌套函数的名字空间(闭包中常见)
    globals 全局变量,函数定义所在模块的名字空间
    builtins 内置模块的名字空间

      

    闭包函数:闭合起来 , 包裹关系,内部函数,包含对外部作用域的一个引用

      1、定义在函数内部的函数

      2、包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包函数

     1 #闭包函数
     2 x=1
     3 def  f1():
     4     x=11111111111
     5     def f2():     #定义在函数f1内部的函数
     6         print(x)  #调用外部作用域的名字x,此x并不是全局下的x
     7     return f2   #任何得地方都可以调用,打破只限于局部使用
     8 
     9 func=f1()  #func 拿到的是f2内存地址,无论func在哪运行,都以x=1111111111 这个值为准
    10 print(func)
    11 
    12 x=100
    13 func()
    14 print(func())  #空值
    15 #f2()称为闭包函数   
    
    #结论
    <function f1.<locals>.f2 at 0x00000000067FFC80>
    11111111111
    11111111111
    None

     闭包函数有什么用

     闭包函数应用:延迟计算、惰性计算

      闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

      应用领域:延迟计算(原来我们是传参,现在我们是包起来)

     1 #爬网页小程序
     2 import requests   #导入request模块
     3 
     4 def get(url):    #定义一个get函数,参数为url
     5     return requests.get(url).text    #返回得到网站内容的文本信息
     6 print(get('http://www.baidu.com'))
     7 
     8 #方法二:
     9 def index(url):    #定义页面函数
    10     def get():     #定义get函数
    11         print(requests.get(url).text)  #输出得到的网站内容文本信息
    12     return get     #返回get信息,即返回网址内容文本信息,使得任意位置可以调用baidu_web = index('http://www.baidu.com')  #调用index()函数
    13 baidu_web()   #执行函数
    14 
    15 #反法三
    16 
    17 def index(url):
    18     x = 'xxxx'
    19     y = 'yyyy'
    20     def wrapper():
    21         x
    22         y
    23         return requests.get(url).text
    24     return wrapper
    25 baidu_web = index('http://www.baidu.com')
    26 baidu = baidu_web.__closure__    #closure 是内部 闭合 函数  , 生成一个元组, 元组内容是 x  y url 的值构成的元素
    27 baidu0 = baidu_web.__closure__[0].cell_contents # 查看元组里面的值
    28 baidu1 = baidu_web.__closure__[1].cell_contents
    29 baidu2 = baidu_web.__closure__[2].cell_contents
    30 print(baidu)
    31 print(type(baidu))
    32 print(baidu0)
    33 print(type(baidu0))
    34 print(baidu1)
    35 print(type(baidu1))        
    36 print(baidu2)
    37 print(type(baidu2))    
    38 
    39 ##结果
    40 (<cell at 0x0000000008DF0C48: str object at 0x0000000008A5C5D0>, <cell at 0x0000000008DF0E88: str object at 0x0000000006782D88>, <cell at 0x0000000008DF0B88: str object at 0x0000000006782F10>)
    41 <class 'tuple'>
    42 http://www.baidu.com
    43 <class 'str'>
    44 xxxx
    45 <class 'str'>
    46 yyyy
    47 <class 'str'>

      

    装饰器   :  (闭包函数的一种应用场景)  装饰他人的工具,装饰器目的是为他人添加新功能

    开放封闭原则:对扩展是开放的,对修改是封闭的

    装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象

    装饰器所遵循的原则:

      1、不修改被装饰对象的源代码

      2、不修改被调用对象的调用方式

    装饰器的目的:

      在循序1和2原则的前提下,为其他新功能函数添加

     1 #装饰器
     2 #统计函数执行时间,函数执行为源代码,新增统计时间
     3 
     4 #@装饰器名A,必须写在被装饰对象B的正上方,并且是单独一行,把正下方的函数名B当做参数传给@后的函数名A,然后吧返回值在赋值给这个函数B
     5 
     6 import time
     7 
     8 def timmer(func):      #装饰器  定义一个timmer函数,参数为 func
     9     # func=index
    10     def wrapper():      #定义wrapper函数
    11         start=time.time()   #开始时间
    12         func()              #运行函数
    13         stop=time.time()    #结束时间
    14         print('run time is %s' %(stop-start))  #统计函数执行时间
    15     return wrapper      #返回函数内存地址
    16 
    17 
    18 @timmer         # 相当于   index=timmer(index)
    19 def index():    # 源代码  定义 index函数  并用  index()方式调用
    20     time.sleep(3)
    21     print('welcome to index')
    22 @timmer         # 相当于  home=timmer(home)
    23 def home():     ## 源代码  定义 home函数  并用  home()方式调用
    24     time.sleep(2)
    25     print('welcome to home page')
    26 
    27 #index=timmer(index)   相当于上面的  @timmer   有其一即可
    28 #home=timmer(home)     相当于上面的  @timmer   有其一即可
    29 
    30 index()    #调用函数
    31 home()
    32 
    33 ####结论 ####
    34 welcome to index
    35 run time is 3.000300168991089
    36 welcome to home page
    37 run time is 2.000199794769287

     上面为无参函数, def index():   def home():      ,如果是有参函数   def home(name):  

    就需要传参,则 

    def wrapper(*args, **kwargs):    #  以保障可以允许任意场景使用

    1 def timmer(func):      #装饰器  定义一个timmer函数,参数为 func
    2     # func=index
    3     def wrapper(*agrs, **kwargs):      #定义wrapper函数,添加参数,
    4         start=time.time()                     #开始时间
    5         func(*agrs, **kwargs)              #运行函数
    6         stop=time.time()                      #结束时间
    7         print('run time is %s' %(stop-start))  #统计函数执行时间
    8     return wrapper     #返回函数内存地址

     无参装饰器

     1 #无参装饰器
     2 #原函数为 index() ,现在添加装饰器,满足登录认证,从文件db.txt中验证账号密码,确认后进入页面  from index
     3 
     4 current_user={'user':None}    # 建立记录用户名的字典
     5 def auth(func):    #定义认证函数,带func参数
     6     def wrapper(*args,**kwargs):   #定义wrapper函数,可传任意参数
     7         if current_user['user']:   #判断用户名
     8             return func(*args,**kwargs)   #返回认证函数 func
     9 
    10         name=input('name: ').strip()  #输入用户名
    11         password=input('password: ').strip() #输入密码
    12 
    13         with open('db.txt', encoding='utf-8') as f:   #打开数据库字典文件
    14             user_dic = eval(f.read())   #eval用来执行f.read()读取函数,并把读取的内网返回给user_dic
    15         if name in user_dic and password == user_dic[name]:  #判断账号密码如果都正确
    16             res=func(*args,**kwargs)    #执行func函数,并赋值给res
    17             current_user['user']=name   #将输入的name传给用户字典
    18             return res   #返回res 内存地址
    19         else:
    20             print('user or password error')   #用户名和密码有错的话,提示有错
    21     return wrapper   #返回wrapper函数内存地址
    22 
    23 @auth #index=auth(index) index=wrapper   #应用装饰器  
    24 def index():    #定义index函数
    25     print('from index')
    26 index()     #执行index函数
     1 #有参装饰器版本
     2 #可以通过多个认证方式认证   file  MySQL 等等
     3 
     4 current_user={'user':None}
     5 def auth(auth_type='file'):
     6     def deco(func):
     7         def wrapper(*args, **kwargs):
     8             if auth_type == 'file':
     9                 if current_user['user']:
    10                     return func(*args, **kwargs)
    11                 name = input('name: ').strip()
    12                 password = input('password: ').strip()
    13 
    14                 with open('db.txt', encoding='utf-8') as f:
    15                     user_dic = eval(f.read())
    16                 if name in user_dic and password == user_dic[name]:
    17                     res = func(*args, **kwargs)
    18                     current_user['user'] = name
    19                     return res
    20                 else:
    21                     print('user or password error')
    22             elif auth_type == 'mysql':
    23                 print('mysql')
    24 
    25             elif auth_type == 'ldap':
    26                 print('ldap')
    27             else:
    28                 print('not valid auth_type')
    29         return wrapper
    30     return deco
    31 @auth(auth_type='mysql') #@deco  #index=deco(index)
    32 def index():
    33     print('from index')
    34 @auth(auth_type='file')
    35 def home(name):
    36     print('welcome %s' %name)
    37 index() #wrapper()
    38 home('egon')

     装饰器补充内容:  ‘’‘   ’‘’  三引号

     查看函数备注可以通过 help 查看 :   print(help(func))

     1 #未加wraps 时
     2 def wrapper(f):   #定义修饰函数
     3     def wrapper_function(*args, **kwargs):
     4         """这个是修饰函数"""
     5         return f(*args, **kwargs)
     6     return wrapper_function
     7     
     8 @wrapper
     9 def wrapped():   #定义被修饰函数
    10     """这个是被修饰的函数"""
    11     print('wrapped')
    12 
    13 print(wrapped.__doc__)  # 输出`这个是修饰函数`
    14 print(wrapped.__name__)  # 输出`wrapper_function`
    15 
    16 ####结果
    17 这个是修饰函数
    18 wrapper_function
     1 # 添加 wraps 后
     2 from functools import wraps
     3 
     4 def wrapper(f):
     5     @wraps(f)   #在最内层的函数上面添加
     6     def wrapper_function(*args, **kwargs):
     7         """这个是修饰函数"""
     8         return f(*args, **kwargs)
     9     return wrapper_function
    10     
    11 @wrapper
    12 def wrapped():
    13     """这个是被修饰的函数
    14     """
    15     print('wrapped')
    16 
    17 print(wrapped.__doc__)  # 输出`这个是被修饰的函数`
    18 print(wrapped.__name__)  # 输出`wrapped`
    19 
    20 ####结果 
    21 这个是被修饰的函数
    22 wrapped

     一个函数头顶上有多个装饰器吗?   可以。

     1 ##多个装饰器
     2 import time
     3 from functools import wraps
     4 
     5 current_user={'user':None}
     6 
     7 def timmer(func):
     8     @wraps(func)
     9     def wrapper(*args,**kwargs):
    10         start=time.time()
    11         res=func(*args,**kwargs)
    12         stop=time.time()
    13         print('run time is %s' %(stop-start))
    14         return res
    15     return wrapper
    16 def auth(auth_type='file'):
    17     def deco(func):
    18         def wrapper(*args, **kwargs):
    19             if auth_type == 'file':
    20                 if current_user['user']:
    21                     return func(*args, **kwargs)
    22                 name = input('name: ').strip()
    23                 password = input('password: ').strip()
    24 
    25                 with open('db.txt', encoding='utf-8') as f:
    26                     user_dic = eval(f.read())
    27                 if name in user_dic and password == user_dic[name]:
    28                     res = func(*args, **kwargs)
    29                     current_user['user'] = name
    30                     return res
    31                 else:
    32                     print('user or password error')
    33             elif auth_type == 'mysql':
    34                 print('mysql')
    35 
    36             elif auth_type == 'ldap':
    37                 print('ldap')
    38             else:
    39                 print('not valid auth_type')
    40         return wrapper
    41     return deco
    42 
    43 # 多个装饰器,那个在前先生效那个
    44 # 直接修饰正下方的函数
    45 @auth() # @deco #index=deco(index) #wrapper
    46 @timmer #index=timmer(wrapper)
    47 # @auth() # @deco #index=deco(index) #wrapper
    48 def index():
    49     '''这是index函数'''
    50     time.sleep(3)
    51     print('welcome to index')
    52     return 123
    53 
    54 # print(index.__doc__)
    55 # print(help(index))
    56 
    57 index()
    58 
    59 
    60 #####结果
    61 name: lalala
    62 password: 123
    63 welcome to index
    64 run time is 3.0002999305725098
     

     ####练习题####

    一:编写函数,(函数执行的时间是随机的)
    二:编写装饰器,为函数加上统计时间的功能
    三:编写装饰器,为函数加上认证的功能

    四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
    注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

    五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录

    六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

    七:为题目五编写装饰器,实现缓存网页内容的功能:
    具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

    扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中

    八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作

    九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
    注意:时间格式的获取
    import time
    time.strftime('%Y-%m-%d %X')

    ######################################

    迭代器 (Iterator):是一个重复的过程,每一次重复,都是基于上一次的结果而来

    取值:就是一个循环的过程,

    依赖于索引的方式迭代取值:字符串 列表 元组

    如列表取值:   

    l=['a','b','c','d']
    count=0
    while count < len(l):
      print(l[count])
      count+=1

    不依赖于索引的方式取值:字典取值(无索引,非序列类型)  该方式就是迭代器

    可迭代对象 iterable:  凡是对象下有  __iter__ 方法: 对象.__iter__ , 该对象就是可迭代对象

    # s='hello'
    # l=['a','b','c','d']
    # t=('a','b','c','d')
    # dic={'name':'egon','sex':'m',"age":18}
    # set1={1,2,3}
    # f=open('db.txt')

    # s.__iter__()
    # l.__iter__()
    # t.__iter__()
    # dic.__iter__()
    # set1.__iter__()
    # f.__iter__()

    执行iter的到的是迭代器对象,是一个内存地址

    迭代器对象有next方法

    使用next方法可以去到字典的key键值

    迭代器对象:

    #1 有__iter__ , 执行得到仍然是迭代本身,执行 iter之后才会有 next
    #2 有__next__  , 一次取一个值

    # l=['a','b','c','d']    列表
    # i=iter(l)              迭代器

    迭代器对象的优点:

    #1:提供了一种统一的,可以不依赖于索引的迭代方式   

    #2:迭代器本身,比起其他数据类型更省内存  (同一时间只有一个值)

    迭代器对象的缺点:
    #1:一次性,只能逐步往后取值,不能回退,不如索引取值灵活
    #2:无法预知什么时候取值结束,即无法预知长度

     文件是迭代器对象,既可以__iter__ , 又可以 __next__

     1 #迭代器
     2 l=['a','b','c','d']     #列表
     3 dic={'name':'lalala','sex':'m',"age":28}  #字典
     4 iter_l=iter(l)      #取值,取的是元素的内存地址
     5 iter_dic=iter(dic)  #取值,取得是字典key键的内存地址
     6 while True:   #建立循环   取值
     7     try:       #消除异常
     8         # print(next(iter_l))   #挨个取列表的值
     9         # print(next(iter_dic))  #取字典的key值
    10         k=next(iter_dic)  #   
    11         print(k,dic[k])   #取字典的key值和value值
    12     except StopIteration:  #如果出现此异常,则终止循环
    13         break
    14 
    15 #### 结果 
    16 name lalala
    17 sex m
    18 age 28
     

     for循环原理

     1 # for循环原理   实际上就是迭代器  for循环比while循坏更便捷
     2 # 先调用__iter__() 方法
     3 # 凡是能被for循环执行循环的,都是可迭代器对象
     4 l = ['a', 'b' , 'c', 'd',]
     5 for item in l : #iter_l = l.__iter__()  #从l中逐个取值,赋值给item, 这里的item可以任意定义
     6     print(item)
     7 
     8 with open('a.txt') as f:   用with方式打开文件
     9     # for line in f: #i=f.__iter__()   #for循环文件内容,调用__iter__(),然后执行next,将结果返回给 line      line = f.__iter__()
    10     #     print(line)
    11     print(f is f.__iter__())   #常见的类型里面,只有文件是迭代器对象,其余都是可迭代器对象,迭代器对象既要有 __iter__(),又要有 next()
     

     生成器   (generator) : 只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码

    生成器就是迭代器,满足迭代器所有的特点,在next()函数才会往下执行

     1 #生成器
     2 #生成器就是迭代器,因此可以这么取值
     3   # res=next(g)
     4   # print(res)
     5 #yield的功能:
     6 # 1 把函数的结果做生迭代器(以一种优雅的方式封装好__iter__,__next__)
     7 # 2 函数暂停与再继续运行的状态是由yield保存
     8 
     9 def func():
    10     print('first')    #
    11     yield 11111111    #碰到 yield赞停,将后面的返回值返回
    12     print('second')    #再次执行的时候,从yield之后开始执行
    13     yield 2222222
    14     print('third')
    15     yield 33333333
    16     print('fourth')
    17 
    18 g=func()   #执行该函数
    19 # print(g)
    20 # next(g)
    21 
    22 # from collections import Iterator
    23 # print(isinstance(g,Iterator))
    24 
    25 # print(next(g))    #可以通过next取值
    26 # print('======>')
    27 # print(next(g))
    28 # print('======>')
    29 # print(next(g))
    30 # print('======>')
    31 # print(next(g))
    32 
    33 for i in g: #i=iter(g)   #可以通过for循环取值
    34     print(i)
    35 
    36 
    37 ####结果
    38 first
    39 11111111
    40 second
    41 2222222
    42 third
    43 33333333
    44 fourth
     
     1 #用生成器实现range功能
     2 # nu = range(1, 10, 2)     range(start, stop, [step])
     3 # l1 = list(nu)
     4 # t1 = tuple(nu)
     5 # print(l1)
     6 # print(t1)
     7 ###结果
     8 #[1, 3, 5, 7, 9]
     9 #(1, 3, 5, 7, 9)
    10 ##########
    11 def range_fun(start, stop, step):
    12     while start < stop :
    13         yield start
    14         start += step
    15 nu = range_fun(1, 10, 2)
    16 # print(nu)   #<generator object range_fun at 0x0000000006B522B0>
    17 # print(next(nu))    #1
    18 # print(next(nu))    #3
    19 
    20 for i in nu:
    21     print(i)
    22 
    23 #####结果
    24 1
    25 3
    26 5
    27 7
    28 9

     实现一个有无穷值的类型:

     1 #实现无穷值函数,该函数的值同一时间在内存中只存在一个值,所以不会撑爆内存
     2 def func(n):
     3     print('=== start ===')
     4     while True:      #死循环
     5         yield n      #生成器,遇到yield 暂停,返回n,内存中同一时间只有这一个值
     6         n+=1
     7 
     8 g=func(0)  #调用函数
     9 
    10 # print(next(g))
    11 # print(next(g))
    12 # print(next(g))
    13 for i in g:   #取值
    14     print(i)
     1 #生成器 实现一个无穷的序列
     2 def my_range(start,stop):
     3     while True:
     4         if start == stop:
     5             raise StopIteration  #满足条件时,抛出异常。 raise 是自己抛出异常 StopIteration
     6         yield start #2   返回 start的值
     7         start+=1 #3  返回值+1
     8 
     9 g=my_range(1,3)
    10 #
    11 # print(next(g))
    12 # print(next(g))
    13 # print(next(g))
    14 
    15 for i in my_range(5,10):  #for循环遇到异常自动停止循环
    16     print(i)
    17 
    18 ###结果
    19 5
    20 6
    21 7
    22 8
    23 

      

    #yield与return的比较?
    #相同:都有返回值的功能
    #不同:return只能返回一次值,而yield可以返回多次值,可以挂起/保存函数的运行状态

     1 #生成器实现过滤功能  
     2 #实现管道符  # python3 tail.py -f access.log | grep 'error'
     3 
     4 import time
     5 
     6 def tail(filepath):
     7     with open(filepath, 'r') as f:
     8         f.seek(0, 2)
     9         while True:
    10             line = f.readline()
    11             if line:
    12                 yield line
    13             else:
    14                 time.sleep(0.2)
    15 
    16 
    17 def grep(pattern,lines):   #定义管道函数,参数patteron表示 |
    18     for line in lines: 
    19         if pattern in line:
    20             print(line,end='')
    21 
    22 grep('error',tail('access.log'))   #读取文件 access.log , 过滤 error , 只显示 error相关


  • 相关阅读:
    TCP 基础知识
    Spring Boot 实战 —— 日志框架 Log4j2 SLF4J 的学习
    MySQL 实战笔记
    Java 基础
    RPM 包的构建
    RPM 包的构建
    9. 桶排序
    8. 基数排序
    7. 计数排序
    6. 快速排序
  • 原文地址:https://www.cnblogs.com/Albert-w/p/10711160.html
Copyright © 2011-2022 走看看