zoukankan      html  css  js  c++  java
  • Python基础(函数部分)

    写在前面



        加勒比海盗今天上映!



    一、函数的基本概念

     - 函数是什么?

        函数,就是一个'锤子',一个具有特定功能的'锤子',使用者可以在适当的时候使用这个'锤子',而不用再去从头做一个'锤子';即可以直接拿来使用;

      函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

      函数能提高应用的模块性,和代码的重复利用率。

     - 不使用函数会有什么问题?

      1.组织结构不清晰,可读性差;

      2.代码冗余;

      3.无法统一管理且维护难度大;

     - 函数的分类

      1.内置函数;Python解释器自带的具有某些基础功能的'锤子';

      2.自定义函数;用户根据需求,自己定义写好的'锤子';

     - 函数的两个阶段

      1.定义阶段;

      2.使用阶段;

    二、函数的定义

     - 为何要定义函数?

      函数即变量,变量必须先定义后使用,未定义而直接引用函数,就相当于在引用一个不存在的变量名,必然会出错;

     - 函数的定义都干了什么?

      只检测语法,不执行代码;

      函数调用阶段才会去执行具体代码;

     - 如何定义函数?

    1 def functionname( parameters ):
    2    "函数_文档字符串"
    3    function_suite
    4    return [expression]

     - 定义函数的三种形式

      1.无参函数;

        应用场景仅仅只是执行一些操作,比如与用户交互,打印;    print()

      2.有参函数;

        需要根据外部传进来的参数,才能执行相应的逻辑;    len(string)

      3.空函数;

        编写代码之初,用来设计代码结构;    def func():pass

     - 三元表达式

    1 x = 1
    2 y = 7
    3 res = x if x > y else y
    4 print(res)
    5 
    6 ---
    7 7

    三、函数的调用

     - 函数的调用

      1.先找到函数名字;

      2.根据 名字+() 调用函数,执行函数体内的代码;

    1 def foo():
    2     print("From foo func")
    3 print(foo)          # 打印foo函数代码的内存地址
    4 foo()
    5 
    6 ---
    7 <function foo at 0x0000000000B5C268>
    8 From foo func

     - 函数调用的三种形式

      1.语句形式:foo()

    1 def my_max(x,y):
    2     res=x if x >y else y
    3     return res
    4 
    5 res = my_max(1,9)
    6 print(res)
    7 
    8 ---
    9 9

      2.表达式形式:3*len('hello')

    1 def my_max(x,y):
    2     res=x if x >y else y
    3     return res
    4 
    5 res = my_max(1,9)*100
    6 print(res)
    7 
    8 ---
    9 900

      3.函数的执行结果当做另外一个函数的参数:range(len('hello'))

    1 def my_max(x,y):
    2     res=x if x >y else y
    3     return res
    4 
    5 res=my_max(my_max(10,20),30)
    6 print(res)
    7 
    8 ---
    9 30

    四、函数的参数

     - 函数参数的分类

       - 形参

        即函数定义处()里的变量标识符;

       - 实参

        即函数调用处()里的变量;

       - 意义

        形参即变量名,实参即变量值;函数调用则将值绑定到形参变量上,函数调用结束,解除绑定;

     - 具体应用

       - 1.位置参数

        按照从左到右的顺序定义的参数;位置实参需要按照顺序一一对应给位置形参传值绑定;

    1 def foo(name,age):
    2     print(name,age)
    3 
    4 foo('alex',20)
    5 
    6 ---
    7 alex 20

       - 2.关键字参数

        按照 key=value 的形式定义实参;位置实参无需按照位置顺序给形参传值;

        注意:关键字实参必须在位置实参右面,并且对同一个形参不能重复传值;

    1 def foo(name,age):
    2     print(name,age)
    3 
    4 foo('alex',age=19)            # ok
    5 
    6 foo(age=19,'alex')            # SyntaxError: positional argument follows keyword argument
    7 
    8 foo('alex',name='egon')       # TypeError: foo() got multiple values for argument 'name'

       - 3.默认参数

        形参在定义时就已经为其赋值,可以传值也可以不传值;经常需要变的参数定义成位置形参,变化较小的参数定义成默认参数(形参)

        注意:

          1. 只在定义时赋值一次;

          2. 默认参数的定义应该在位置形参右面;

          3. 默认参数通常应该定义成不可变类型

    1 def foo(name,gender='male'):
    2     print(name,gender)
    3 
    4 foo('alex')
    5 foo('kelly','female')
    6 
    7 ---
    8 alex male
    9 kelly female

         - 4.可变长参数

        参考:egon函数草稿

        针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(形参)

        而实参有按位置按关键字两种形式定义,针对这两种形式的可变长,形参也应该有两种解决方案,分别是 *args**kwargs

        - 按位置的可变长参数示例1:

     1 # * 会把溢出的按位置定义的实参都接收,以元组的形式赋值给args,可以通过 *args 得到溢出的各个参数;
     2 def foo(x,y,*args):
     3     print("x -> {}, y -> {}, args -> {}".format(x,y,args))
     4     print("*args is: ", *args)
     5 
     6 foo(1,2)
     7 foo(1,2,3)
     8 foo(1,2,[1,2],{'k1':'v1'},10,'AAAAA')
     9 
    10 ---
    11 x -> 1, y -> 2, args -> ()
    12 *args is: 
    13 x -> 1, y -> 2, args -> (3,)
    14 *args is:  3
    15 x -> 1, y -> 2, args -> ([1, 2], {'k1': 'v1'}, 10, 'AAAAA')
    16 *args is:  [1, 2] {'k1': 'v1'} 10 AAAAA

         - 按位置的可变长参数示例2:

     1 def foo(x, y, *args):
     2     print(x, y)
     3     print(args)
     4     print(*args)
     5 
     6 foo(1, 2, *[3, 4, 5])
     7 
     8 ---
     9 1 2
    10 (3, 4, 5)
    11 3 4 5

         - 按位置的可变长参数示例3:

    1 def foo(x, y, z):
    2     print(x, y, z)
    3 
    4 foo(100,*(2, 3,))
    5 
    6 ---
    7 100 2 3

        - 按位置的可变长参数示例4:

    1 def foo(x, y, z):
    2     print(x, y, z)
    3 
    4 foo(*(1,2, 3,))
    5 foo(*[1,2, 3,])
    6 
    7 ---
    8 1 2 3
    9 1 2 3

        - 按位置的可变长参数示例5:

     1 def foo(x,y,*args):
     2     print("x -> {}, y -> {}, args -> {}".format(x,y,args))
     3     for item in args:
     4         print(type(item),item)
     5     print('------------------------')
     6 
     7 foo(1,2,[1,2],{'k1':'v1'},10,'AAAAA')
     8 
     9 ---
    10 x -> 1, y -> 2, args -> ([1, 2], {'k1': 'v1'}, 10, 'AAAAA')
    11 <class 'list'> [1, 2]
    12 <class 'dict'> {'k1': 'v1'}
    13 <class 'int'> 10
    14 <class 'str'> AAAAA
    15 ------------------------

        - 按关键字的可变长参数示例1:

     1 # ** 会把溢出的按关键字定义的实参都接收,以字典的形式赋值给 kwargs
     2 def foo(x, y, **kwargs):
     3     print(x, y)
     4     print(kwargs)
     5     print(*kwargs)
     6 
     7 foo(1, y=2, a=1, b=2, c=3)
     8 
     9 ---
    10 1 2
    11 {'a': 1, 'c': 3, 'b': 2}
    12 a c b

        - 按关键字的可变长参数示例2:

     1 def foo(x, y, **kwargs):
     2     print(x, y)
     3     print(kwargs)
     4     print(*kwargs)
     5 
     6 foo(1, y=2, **{'a': 1, 'b': 2, 'c': 3})
     7 
     8 ---
     9 1 2
    10 {'a': 1, 'c': 3, 'b': 2}
    11 a c b

        - 按关键字的可变长参数示例3:

    1 def foo(x, y, z):
    2     print("x is %s
    y is %s
    z is %s" % (x, y, z))
    3 
    4 foo(**{'z': 1, 'x': 2, 'y': 3})
    5 
    6 ---
    7 x is 2
    8 y is 3
    9 z is 1

        - 按关键字的可变长参数示例4:

    1 def foo(x, y, z):
    2     print("x is %s
    y is %s
    z is %s" % (x, y, z))
    3 
    4 foo(x=99,**{'z': 1, 'y': 3})
    5 
    6 ---
    7 x is 99
    8 y is 3
    9 z is 1

        - 按关键字的可变长参数示例5:

     1 # ** 会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs;可以通过 *kwargs 得到溢出的参数的key值;但不能用 **kwargs 获取其中的值;
     2 def foo(x,y,**kwargs):
     3     print("x -> {}, y -> {}, kwargs -> {}".format(x, y, kwargs))
     4     print(*kwargs)
     5     for key,value in kwargs.items():
     6         print(key,value)
     7     print('------------------------')
     8 
     9 foo(1,y=9)
    10 foo(x=1,y=9)
    11 foo(1,y=9,m=88,n=99)
    12 foo(1,y=9,m=[3,4],n={'k1':'v1'},l=(1,2,))
    13 
    14 ---
    15 x -> 1, y -> 9, kwargs -> {}
    16 
    17 ------------------------
    18 x -> 1, y -> 9, kwargs -> {}
    19 
    20 ------------------------
    21 x -> 1, y -> 9, kwargs -> {'n': 99, 'm': 88}
    22 n m
    23 n 99
    24 m 88
    25 ------------------------
    26 x -> 1, y -> 9, kwargs -> {'n': {'k1': 'v1'}, 'm': [3, 4], 'l': (1, 2)}
    27 n m l
    28 n {'k1': 'v1'}
    29 m [3, 4]
    30 l (1, 2)
    31 ------------------------

       - 5.命名关键字参数

        - * 后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递; 可以保证,传入的参数中一定包含某些关键字;

        - 命名关键字参数示例1:

     1 def foo(name,age,*,sex='male',height):
     2     print(name,age)
     3     print(sex)
     4     print(height)
     5 
     6 foo('egon',17,height='185')
     7 print('---------')
     8 foo('egon',17,sex='female',height='185')
     9 
    10 ---
    11 egon 17
    12 male
    13 185
    14 ---------
    15 egon 17
    16 female
    17 185

         - 命名关键字参数示例2:

     1 def foo(x, y, *args, a=1, b, **kwargs):
     2     print(x, y)
     3     print(args)
     4     print(a)
     5     print(b)
     6     print(kwargs)
     7 
     8 foo(1, 2, 3, 4, 5, b=3, c=4, d=5)
     9 
    10 ---
    11 1 2
    12 (3, 4, 5)
    13 1
    14 3
    15 {'d': 5, 'c': 4}

        - 命名关键字参数示例3:

     1 def foo(name,age=10,*args,sex='male',height,**kwargs):
     2     print(name)
     3     print(age)
     4     print(args)
     5     print(sex)
     6     print(height)
     7     print(kwargs)
     8 
     9 foo('alex',1,2,3,4,5,sex='female',height='150',a=1,b=2,c=3)
    10 
    11 ---
    12 alex
    13 1
    14 (2, 3, 4, 5)
    15 female
    16 150
    17 {'c': 3, 'a': 1, 'b': 2}

      - 扩展和思考

    1 def foo(x,y):
    2     print(x,y)
    3 
    4 foo(**{'y': 2, 'x': 100})   # 等价于 foo(x=100,y=2)
    5 
    6 ---
    7 100 2
    1 def foo(x,y,z):
    2     print(x,y,z)
    3 
    4 foo(*[1,2,3])               #foo(1,2,3)
    5 foo(*(1,2,3))               #foo(1,2,3)
    6 
    7 ---
    8 1 2 3
    9 1 2 3
    1 def foo(*args):
    2     print(args)
    3     print(*args)
    4 
    5 foo(1,2,4)
    6 
    7 ---
    8 (1, 2, 4)
    9 1 2 4
    1 def foo(**kwargs):
    2     print(kwargs)
    3     print(*kwargs)
    4 
    5 foo(x=1,y=['a','b','c'],z='hello')
    6 
    7 ---
    8 {'y': ['a', 'b', 'c'], 'x': 1, 'z': 'hello'}
    9 y x z
    1 def wrapper(*args,**kwargs):
    2     print(args)
    3     print(kwargs)
    4 
    5 wrapper(1,2,3,a=1,b=2)
    6 
    7 ---
    8 (1, 2, 3)
    9 {'a': 1, 'b': 2}

    五、函数对象

      - 1 可以被引用

     1 def foo():
     2     print('from foo')
     3 
     4 func=foo
     5 print(foo)
     6 print(func)
     7 func()
     8 
     9 ---
    10 <function foo at 0x0000000000B6C268>
    11 <function foo at 0x0000000000B6C268>
    12 from foo

      - 2 可以当作参数传递

     1 def foo():
     2     print('from foo')
     3 
     4 def bar(func):
     5     print(func)
     6     func()
     7 
     8 bar(foo)
     9 
    10 ---
    11 <function foo at 0x000000000072C268>
    12 from foo

      - 3 返回值可以是函数

     1 def foo():
     2     print('from foo')
     3 def bar(func):
     4     return func
     5 
     6 f=bar(foo)
     7 print(f)
     8 f()
     9 
    10 ---
    11 <function foo at 0x00000000010DC268>
    12 from foo

      - 4 可以当作容器类型的元素

     1 # 可以当做容器类的元素
     2 def select():
     3     print('---->>> select')
     4 def update():
     5     print('---->>> update')
     6 def delete():
     7     print('---->>> delete')
     8 def insert():
     9     print('---->>> insert')
    10 
    11 func_dict = {
    12     'select':select,
    13     'update':update,
    14     'delete':delete,
    15     'insert':insert
    16 }
    17 
    18 def main():
    19     while True:
    20         sql = input(">>> ").strip()
    21         if not sql:
    22             continue
    23         elif 'Q' == sql.upper():
    24             print('Bye...')
    25             exit(0)
    26         else:
    27             cmd_list = sql.split()
    28             if cmd_list[0] in func_dict:
    29                 func_dict[cmd_list[0]]()
    30             else:
    31                 print('Input invalid')
    32 
    33 main() 

    六、函数的嵌套

      - 嵌套调用

     1 def max2(x,y):
     2     return x if x > y else y
     3 def max4(a,b,c,d):
     4     res1=max2(a,b)
     5     res2=max2(res1,c)
     6     res3=max2(res2,d)
     7     return res3
     8 
     9 print(max4(10,99,31,22))
    10 
    11 ---
    12 99

      - 嵌套定义

     1 def f1():
     2     print('from f1')
     3     def f2():
     4         print('from f2')
     5         def f3():
     6             print('from f3')
     7         f3()
     8     f2()
     9 
    10 f1()
    11 
    12 ---
    13 from f1
    14 from f2
    15 from f3

    七、命名空间和作用域

    参考:Python命名空间的本质

      - 命名空间

        - 1.内置名称空间:随着Python解释器的启动而产生;会一直保留,直到Python解释器退出;

    1 print(max([1,2,3]))
    1 import builtins
    2 for i in dir(builtins):
    3     print(i)
      1 ArithmeticError
      2 AssertionError
      3 AttributeError
      4 BaseException
      5 BlockingIOError
      6 BrokenPipeError
      7 BufferError
      8 BytesWarning
      9 ChildProcessError
     10 ConnectionAbortedError
     11 ConnectionError
     12 ConnectionRefusedError
     13 ConnectionResetError
     14 DeprecationWarning
     15 EOFError
     16 Ellipsis
     17 EnvironmentError
     18 Exception
     19 False
     20 FileExistsError
     21 FileNotFoundError
     22 FloatingPointError
     23 FutureWarning
     24 GeneratorExit
     25 IOError
     26 ImportError
     27 ImportWarning
     28 IndentationError
     29 IndexError
     30 InterruptedError
     31 IsADirectoryError
     32 KeyError
     33 KeyboardInterrupt
     34 LookupError
     35 MemoryError
     36 NameError
     37 None
     38 NotADirectoryError
     39 NotImplemented
     40 NotImplementedError
     41 OSError
     42 OverflowError
     43 PendingDeprecationWarning
     44 PermissionError
     45 ProcessLookupError
     46 RecursionError
     47 ReferenceError
     48 ResourceWarning
     49 RuntimeError
     50 RuntimeWarning
     51 StopAsyncIteration
     52 StopIteration
     53 SyntaxError
     54 SyntaxWarning
     55 SystemError
     56 SystemExit
     57 TabError
     58 TimeoutError
     59 True
     60 TypeError
     61 UnboundLocalError
     62 UnicodeDecodeError
     63 UnicodeEncodeError
     64 UnicodeError
     65 UnicodeTranslateError
     66 UnicodeWarning
     67 UserWarning
     68 ValueError
     69 Warning
     70 WindowsError
     71 ZeroDivisionError
     72 __build_class__
     73 __debug__
     74 __doc__
     75 __import__
     76 __loader__
     77 __name__
     78 __package__
     79 __spec__
     80 abs
     81 all
     82 any
     83 ascii
     84 bin
     85 bool
     86 bytearray
     87 bytes
     88 callable
     89 chr
     90 classmethod
     91 compile
     92 complex
     93 copyright
     94 credits
     95 delattr
     96 dict
     97 dir
     98 divmod
     99 enumerate
    100 eval
    101 exec
    102 exit
    103 filter
    104 float
    105 format
    106 frozenset
    107 getattr
    108 globals
    109 hasattr
    110 hash
    111 help
    112 hex
    113 id
    114 input
    115 int
    116 isinstance
    117 issubclass
    118 iter
    119 len
    120 license
    121 list
    122 locals
    123 map
    124 max
    125 memoryview
    126 min
    127 next
    128 object
    129 oct
    130 open
    131 ord
    132 pow
    133 print
    134 property
    135 quit
    136 range
    137 repr
    138 reversed
    139 round
    140 set
    141 setattr
    142 slice
    143 sorted
    144 staticmethod
    145 str
    146 sum
    147 super
    148 tuple
    149 type
    150 vars
    151 zip
    Python解释器启动后,加载的内置名称空间所包含的变量

        - 2.全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间;在文件/模块被Python解释器读入时创建,通常也会一直保存到解释器退出;

        - 3.局部名称空间:调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定;

     1 info = "Adress : "
     2 def func_father(country):
     3     def func_son(area):
     4         city= "Shanghai "                       #此处的city变量,覆盖了父函数的city变量
     5         print(info + country + city + area)
     6     city = " Beijing "
     7     #调用内部函数
     8     func_son("ChaoYang ");
     9  
    10 func_father("China ")
    11 
    12 ---
    13 Adress : China Shanghai ChaoYang

      - 作用域

        - 1.全局作用域

          包含内置名称空间和全局名称空间;

          查看全局作用域内的名字:gloabls()

          生命周期:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕;

        - 2.局部作用域

          只包含局部名称空间;

          查看局局作用域内的名字:locals()

          生命周期:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效;

        - 3.名字的查找顺序

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

    如果 Python 在这些名字空间找不到 x,它将放弃查找并引发一个 NameError 异常,如,NameError: name 'aa' is not defined;

         示例:

     1 x=1000
     2 def func():
     3     x=2
     4     y=('a','b',)
     5     print(x,y)
     6     print(globals())
     7     print(locals())
     8 func()
     9 
    10 ---
    11 2 ('a', 'b')
    12 {'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000565C88>, 'func': <function func at 0x00000000006EC268>, '__file__': 'D:/soft/work/Python_17/day04/functions.py', '__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__cached__': None, '__package__': None, 'x': 1000, '__spec__': None}
    13 {'y': ('a', 'b'), 'x': 2}

    八、闭包的概念

      - 闭包的定义

        1. 定义在函数内部的函数;

        2. 该内部函数包含对外部作用域而不是对全局作用域的引用;

        - 扩展:

          __closure__ 属性定义的是一个包含 cell 对象的元组,其中元组中的每一个 cell 对象用来保存作用域中变量的值;

     1 def f1():
     2     x = 1
     3     user_list = ['alex','egon']
     4     def f2():
     5         print(x)
     6         print(user_list)
     7     return f2
     8 
     9 f = f1()                          # 返回一个闭包函数对象:即f2;
    10 print(f)
    11 print(f.__closure__)              # 查看该闭包函数所包含的元素;
    12 for item in f.__closure__:
    13     print(item)
    14     print(item.cell_contents)   # 打印出每一个元素的值
    15 
    16 ---
    17 <function f1.<locals>.f2 at 0x00000000006CC400>
    18 (<cell at 0x0000000000697D68: list object at 0x00000000006D0F48>, <cell at 0x0000000000697D98: int object at 0x0000000060BE01D0>)
    19 <cell at 0x0000000000697D68: list object at 0x00000000006D0F48>
    20 ['alex', 'egon']
    21 <cell at 0x0000000000697D98: int object at 0x0000000060BE01D0>
    22 1

      - 闭包的意义

        - 返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域;

        - 这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域;

      - 应用领域:延迟计算/惰性计算

        - f = index('http://www.baidu.com')  这样只是得到了一个函数对象,并没有执行具体操作,需要执行的时候直接使用 f() 即可;

     1 # 内部函数包含对外部作用域而非全局作用域的引用;
     2 # 返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域;
     3 # 闭包应用:惰性计算/延迟计算
     4 from urllib.request import urlopen
     5 
     6 def index(url):
     7     def get():
     8         return urlopen(url).read()
     9     return get
    10 
    11 f = index('http://www.baidu.com')
    12 print(f.__closure__)
    13 print(f.__closure__[0].cell_contents)
    14 
    15 # print(f())
    16 print(f().decode('utf-8'))

    九、装饰器

    参考:Advanced Uses of Python Decorators

      - 什么是装饰器?

        - 修饰别人的工具,在原来基础上修饰添加功能;

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

      - 为什么要用装饰器?

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

        - 装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能;

      - 装饰器应用

        - 示例:

     1 # 开放封闭原则:对修改封闭,对扩展开放;
     2 # 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象;
     3 # 装饰器就是闭包的一种实现,只不过参数是函数对象;
     4 
     5 import time
     6 
     7 def timer(func):
     8     def wrapper():
     9         start_time = time.time()
    10         func()
    11         end_time = time.time()
    12         print('Run time is {}'.format(end_time-start_time))
    13     return wrapper
    14 
    15 @timer # 等价于 index = timer(index)
    16 def index():
    17     print('Start to work...')
    18     time.sleep(3)
    19     print('End the work...')
    20 
    21 index()
    22 
    23 ---
    24 Start to work...
    25 End the work...
    26 Run time is 3.0

        - 原理分析:

          1.在 index()函数定义的正上方加上 @timer,即表示用 timer()函数来装饰 index()函数;

          2.加上 @timer 后,再调用 index()的时候就相当于:timer(index);而 timer(index) 的返回值是 wrapper() 函数;

          3.所以装饰之后,调用index() 等价于 调用 wrapper(),而wrapper()是一种闭包,包含了timer函数里参数(即 index)的引用;

        - 装饰器扩展示例1:被装饰的对象(本例中就是函数),可以有参数返回值

     1 import time
     2 
     3 def timer(func):
     4     def wrapper(*args,**kwargs):
     5         start_time = time.time()
     6         res = func(*args,**kwargs)
     7         end_time = time.time()
     8         print('Run time is {}'.format(end_time-start_time))
     9         return res
    10     return wrapper
    11 
    12 @timer # 等价于 index = timer(index)
    13 def index():
    14     time.sleep(3)
    15     print('Welcome hahaha...')
    16     return 123
    17 
    18 res = index()
    19 print(res)
    20 
    21 print('---------------')
    22 
    23 @timer # 等价于 foo = timer(foo)
    24 def foo(name):
    25     time.sleep(1)
    26     print('From foo func...')
    27     return '--->>> ' + name
    28 
    29 res = foo('standby')
    30 print(res)
    31 
    32 ---
    33 Welcome hahaha...
    34 Run time is 3.0
    35 123
    36 ---------------
    37 From foo func...
    38 Run time is 1.0
    39 --->>> standby

         - 装饰器扩展示例2:要求用户输入用户名密码,验证通过才能进行相关操作;

     1 def auth_user(func):
     2     def wrapper(*args,**kwargs):
     3         u_name = input('Name is >>>	'.expandtabs(20))
     4         u_pwd = input('Password is >>>	'.expandtabs(20))
     5         if 'standby' == u_name and '123' == u_pwd:
     6             res = func(*args,**kwargs)
     7             return res
     8         else:
     9             print('Invalid input...')
    10     return wrapper
    11 
    12 @auth_user
    13 def index():
    14     print('Welcome to index page...')
    15 
    16 res1 = index()
    17 print(res1)
    18 
    19 print('--------------')
    20 
    21 @auth_user
    22 def home(name):
    23     print('{}, welcome to index page...'.format(name))
    24     return '--->>> ' + name
    25 res2 = home('standby')
    26 print(res2)
    27 
    28 ---
    29 Name is >>>         standby
    30 Password is >>>     123
    31 Welcome to index page...
    32 None
    33 --------------
    34 Name is >>>         standby
    35 Password is >>>     123
    36 standby, welcome to index page...
    37 --->>> standby

        - 装饰器扩展示例3:有参装饰器

     1 user_dict = {
     2     'name':None,
     3     'status':False
     4 }
     5 
     6 def auth_type(type='ldap'):
     7     def auth(func):
     8         def wrapper(*args,**kwargs):
     9             if user_dict['name'] and user_dict['status']:
    10                 res = func(*args, **kwargs)
    11                 return res
    12             else:
    13                 name = input('Name >>> ')
    14                 pwd = input('Pass >>> ')
    15                 if 'ldap' == type:
    16                     print('ldap')
    17                     if 'standby' == name and '123' == pwd:
    18                         user_dict['name'] = name
    19                         user_dict['status'] = True
    20                         res = func(*args,**kwargs)
    21                         return res
    22                     else:
    23                         print('auth failed...')
    24                 elif 'mysql' == type:
    25                     print('mysql')
    26                     if 'standby' == name and '123' == pwd:
    27                         user_dict['name'] = name
    28                         user_dict['status'] = True
    29                         res = func(*args,**kwargs)
    30                         return res
    31                     else:
    32                         print('auth failed...')
    33                 else:
    34                     print('Invalid auth type.')
    35         return wrapper
    36     return auth
    37 
    38 @auth_type('ldap')
    39 def index():
    40     print('Welcome to index page.')
    41 
    42 @auth_type('mysql')
    43 def home(name):
    44     print('{}, welcome home.'.format(name))
    45     return 'Hello ' + name
    46 index()
    47 res = home('standby')
    48 print(res)

        - 装饰器扩展示例4:装饰器叠加

     1 def decorator1(func):
     2     def wrapper():
     3         print('hello python, from decorator1')
     4         func()
     5     return wrapper
     6 
     7 def decorator2(func):
     8     def wrapper():
     9         func()
    10         print('hello python, from decorator2')
    11     return wrapper
    12 
    13 @decorator1
    14 @decorator2
    15 def test():
    16     print('hello python!')
    17 
    18 test()
    19 
    20 ---
    21 hello python, from decorator1
    22 hello python!
    23 hello python, from decorator2

    十、迭代器

      - 迭代的概念

    1 迭代器
    2 迭代的概念:重复+上一次迭代的结果为下一次迭代的初始值
    3 重复的过程称为迭代,每次重复即一次迭代,
    4 并且每次迭代的结果是下一次迭代的初始值

      - 为什么要有迭代器?

        为什么要有迭代器?

        对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式;

      - 可迭代对象 和 迭代器对象

        - 可迭代对象

          - 只要它定义了可以返回一个迭代器的__iter__方法(即:内置__iter__方法的),那么他就是可迭代对象;

          - 如下所示:list str tuple dict set 这些都是可迭代对象:

     1 iter1 = [1,2].__iter__()
     2 iter2 = 'hello'.__iter__()
     3 iter3 = (1,2).__iter__()
     4 iter4 = {'a':1,'b':2}.__iter__()
     5 iter5 = {1,2,3}.__iter__()
     6 print(type(iter1))
     7 print(type(iter2))
     8 print(type(iter3))
     9 print(type(iter4))
    10 print(type(iter5))
    11 
    12 ---
    13 <class 'list_iterator'>
    14 <class 'str_iterator'>
    15 <class 'tuple_iterator'>
    16 <class 'dict_keyiterator'>
    17 <class 'set_iterator'>

        - 迭代器对象

          - 执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法;

          - 迭代器是通过  next()  来实现的,每调用一次他就会返回下一个元素,当没有下一个元素的时候返回一个 StopIteration异常;

     1 i = {'k1':1,'k2':9,'k3':7}.__iter__()
     2 print(type(i))
     3 print(i)
     4 print(i.__next__())
     5 print(i.__next__())
     6 print(i.__next__())
     7 # print(i.__next__()) #抛出异常:StopIteration
     8 
     9 ---
    10 <class 'dict_keyiterator'>
    11 <dict_keyiterator object at 0x00000000006C3778>
    12 k2
    13 k3
    14 k1

      示例1:

     1 dic = {
     2     'k1':'v1',
     3     'k2':'v2',
     4 }
     5 
     6 f = dic.__iter__()                  # 得到一个迭代器对象 f
     7 print(type(f))                      # 迭代器类型
     8 print(f)                     
     9 print(f.__iter__())                 # f.__iter__() 得到的还是 f 自身;(迭代器执行 __iter__() 得到的还是迭代器自身)
    10 print(f.__next__())                 # 迭代dic,获取 key 
    11 print(f.__next__())
    12 
    13 ---
    14 <class 'dict_keyiterator'>
    15 <dict_keyiterator object at 0x00000000006D2778>
    16 <dict_keyiterator object at 0x00000000006D2778>
    17 k1
    18 k2

      示例二: 模拟字典的for循环

     1 dic={'a':1,'b':2,'c':3}
     2 i=dic.__iter__()
     3 while True:
     4     try:
     5         key=i.__next__()                    # 获取dic的key
     6         print(dic[key])                     # 根据key获取对应的value
     7     except StopIteration:
     8         break
     9 
    10 ---
    11 2
    12 3
    13 1

      示例三: 枚举类型也是迭代器

     1 l=[10000,2,3,4,5]
     2 
     3 i=enumerate(l)
     4 print(type(i),i)
     5 print(next(i))
     6 print(next(i))
     7 print(next(i))
     8 print(next(i))
     9 print(next(i))
    10 
    11 ---
    12 <class 'enumerate'> <enumerate object at 0x0000000000A10AF8>
    13 (0, 10000)
    14 (1, 2)
    15 (2, 3)
    16 (3, 4)
    17 (4, 5)

       - 扩展示例:  len()  等价于 __len__()

    1 s='hello'
    2 print(s.__len__())
    3 print(len(s))
    4 
    5 ---
    6 5
    7 5

      - 哪些是可迭代的对象?

     1 #如何判断一个对象是可迭代的对象,还是迭代器对象
     2 from collections import Iterable,Iterator
     3 
     4 'abc'.__iter__()                              # 具有 __iter__() 方法的都是可迭代对象
     5 ().__iter__()
     6 [].__iter__()
     7 {'a':1}.__iter__()
     8 {1,2}.__iter__()
     9 f=open('a.txt',mode='r',encoding='utf-8')
    10 f.__iter__()
    11 
    12 
    13 # 判断是否是可迭代的对象
    14 print(isinstance('abc',Iterable))
    15 print(isinstance([],Iterable))
    16 print(isinstance((),Iterable))
    17 print(isinstance({'a':1},Iterable))
    18 print(isinstance({1,2},Iterable))
    19 print(isinstance(f,Iterable))
    20 
    21 print('--------------------')
    22 # 判断是否是迭代器对象
    23 print(isinstance('abc',Iterator))
    24 print(isinstance([],Iterator))
    25 print(isinstance((),Iterator))
    26 print(isinstance({'a':1},Iterator))
    27 print(isinstance({1,2},Iterator))
    28 print(isinstance(f,Iterator))                # 只有文件对象是迭代器对象
    29 
    30 ---
    31 True
    32 True
    33 True
    34 True
    35 True
    36 True
    37 --------------------
    38 False
    39 False
    40 False
    41 False
    42 False
    43 True

      - 迭代器优缺点

    1 迭代器的优点和缺点
    2 优点:
    3     1.提供了一种不依赖下标的迭代方式;
    4     2.就跌迭代器本身来说,更节省内存,每次只把一个元素放入内存中,依次迭代,而非全部放入内存中;
    5 
    6 缺点:
    7     1. 无法获取迭代器对象的长度;
    8     2. 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退;

      - 迭代器协议

        - 对象有__next__()方法,即 next();

        - 对象有__iter__()方法,对于迭代器对象来说,执行__iter__()方法,得到的结果仍然是它本身;

      - 迭代器应用

        - for循环遍历

     1 dic={'name':'egon','age':18,'height':'180'}
     2 print(dic.items())
     3 for k,v in dic.items():
     4     print(k,v)
     5 
     6 ---
     7 dict_items([('age', 18), ('name', 'egon'), ('height', '180')])
     8 age 18
     9 name egon
    10 height 180

        - 迭代器内部实现

     1 dic={'name':'egon','age':18,'height':'180'}
     2 i=iter(dic)
     3 while True:
     4     try:
     5         k=next(i)
     6         print(k + " " + str(dic[k]))
     7     except StopIteration:
     8         break
     9 
    10 ---
    11 name egon
    12 age 18
    13 height 180

    十一、生成器

      - 什么是生成器?

        - 只要函数体包含yield关键字,该函数就是生成器函数;

        - 生成器就是迭代器;生成器是构造迭代器的最简单有力的工具,与普通函数不同的只有在返回一个值的时候使用yield来替代return,然后yield会为函数封装好 next() 和 iter();

        - 外部通过调用 next() 来触发迭代器(函数)的执行;

        - yield 语句可以让普通函数变成一个生成器,并且相应的 __next__() 方法返回的是 yield 后面的值。

        - 一种更直观的解释是:程序执行到 yield 会返回值并暂停,再次调用 next() 时会从上次暂停的地方继续开始执行;

    1 return只能返回一次值,函数就终止了;
    2 yield能返回多次值,每次返回都会将函数暂停;
    3 下一次next会从上一次暂停的位置继续执行

      - 示例:

        - 示例1:

     1 def foo():
     2     print('first')
     3     yield 1
     4     print('second')
     5     yield 2
     6     print('third')
     7     yield 3
     8     print('fourth')
     9     yield 4
    10     print('fifth')
    11 
    12 g=foo()
    13 print(type(g))
    14 print(g)
    15 print(next(g)) #触发迭代器g的执行,进而触发函数的执行
    16 print(next(g))
    17 print(next(g))
    18 print(next(g))
    19 # print(next(g)) # StopIteration 异常
    20 
    21 ---
    22 <class 'generator'>
    23 <generator object foo at 0x00000000007DB468>
    24 first
    25 1
    26 second
    27 2
    28 third
    29 3
    30 fourth
    31 4

        - 示例2:   

     1 def foo():
     2     print('first')
     3     yield 1
     4     print('second')
     5     yield 2
     6     print('third')
     7     yield 3
     8     print('fourth')
     9     yield 4
    10     print('fifth')
    11 
    12 g=foo()                            # 得到一个生成器;
    13 print(type(g))
    14 print(g)
    15 for i in g:                        # 遍历这个生成器;
    16     print("返回值是 %s" % i)
    17 
    18 ---
    19 <class 'generator'>
    20 <generator object foo at 0x00000000010EB4C0>
    21 first
    22 返回值是 1
    23 second
    24 返回值是 2
    25 third
    26 返回值是 3
    27 fourth
    28 返回值是 4
    29 fifth

      - 生成器应用

     1 # 模拟Linux中命令:tail -f a.txt | grep 'python'
     2 
     3 import time
     4 def tail(filepath):
     5     with open(filepath,encoding='utf-8') as f:
     6         f.seek(0,2)                      # 定位到文件末尾
     7         while True:
     8             line=f.readline().strip()    # 从最后一行开始读内容
     9             if line:                     # 如果读到内容则返回该行内容,然后进入下一轮 while循环,并暂停,等待下一次调用;
    10                 yield line
    11             else:
    12                 time.sleep(0.2)
    13 
    14 def grep(pattern,lines):
    15     for line in lines:                   # 循环tail函数中yield返回的文件新增内容;
    16         if pattern in line:              # 如果包含关键字 patten,则返回该行内容,然后进入下一次for循环并暂停在这一步,等待下一次调用;
    17             yield line
    18 
    19 g=grep('python',tail('a.txt'))           # patten 即 'python'
    20 print(g)                                 # 得到一个生成器对象:<generator object grep at 0x0000000000A3B570>
    21 for i in g:                              # 遍历该生成器(即 迭代器),循环调用 grep() 和 tail() 函数;
    22     print(i)                             # 将grep()函数返回的内容打印出来;

    十二、练习

    要求:

      操作文件:haproxy.cfg,实现对这个文件配置的新增、删除以及查询的功能;

      - 新增的时候要考虑backend是否已存在,没有则新增backend;有则在进一步判断是否存在响应的record,有则不能重复插入,没有则可以插入;

      - 删除的时候要判断是否存在用户想要删除的record,不存在则反馈用户提示信息;存在的话就需要考虑backend含有几个record,大于1个,则删除record,如果只有1个record,则需要把record和backend都要删除;

      - 查询则是列出用户所输入的backend下的所有record信息;

    代码实现:

      1 #!/usr/bin/python
      2 # -*- coding:utf-8 -*-
      3 
      4 
      5 def get_backend_dict():
      6     with open('haproxy.cfg',mode='r',encoding='utf-8') as rf:
      7         content_list = rf.readlines()
      8     backend_dict = {}
      9     for i in range(0, len(content_list)):
     10         if content_list[i].startswith('backend '):
     11             backend_dict[content_list[i].split()[1]] = i
     12     return content_list,backend_dict
     13 
     14 def select(data):
     15     content_list,backend_dict = get_backend_dict()
     16     if data not in backend_dict:
     17         print('No backend record found.')
     18     else:
     19         for i in range(backend_dict[data],len(content_list)-1):
     20             if content_list[i+1].startswith('backend '):
     21                 return
     22             print(content_list[i+1],end='')
     23 
     24 def add(data):
     25     content_list,backend_dict = get_backend_dict()
     26     sub_record_info = "        server " + data['record']['server'] + " " 
     27                       + data['record']['server'] + " weight " 
     28                       + str(data['record']['weight']) + " maxcon " 
     29                       + str(data['record']['maxcon']) + "
    "
     30     backend_info = "
    " + "backend " + data['backend'] + "
    " + sub_record_info
     31     if data['backend'] in backend_dict:
     32         index = -1
     33         tmp_list = []
     34         print('The backend:{} already exist, now to append a record...'.format(data['backend']))
     35         for i in range(backend_dict[data['backend']],len(content_list)-1):
     36             if content_list[i+1].startswith('backend '):
     37                 index = i
     38                 break
     39             else:
     40                 tmp_list.append(content_list[i+1])
     41         if sub_record_info not in tmp_list:
     42             if -1 == index:
     43                 content_list.append(sub_record_info)
     44             else:
     45                 content_list.insert(index,sub_record_info)
     46             with open('haproxy.cfg', mode='w', encoding='utf-8') as wf:
     47                 wf.writelines(content_list)
     48             print("The backend:{} already exist, append a record successfully.".format(data['backend']))
     49         else:
     50             print("The record:{} already exist, add failed.".format(sub_record_info.strip()))
     51     else:
     52         with open('haproxy.cfg',mode='a+',encoding='utf-8') as wf:
     53             wf.write(backend_info)
     54         print("New backend added successfully.")
     55 
     56 def remove(data):
     57     content_list, backend_dict = get_backend_dict()
     58     if data['backend'] not in backend_dict:
     59         print("The backend:{} doesn't exist, remove failed.".format(data['backend']))
     60     else:
     61         tmp_list = []
     62         sub_record_info = "        server " + data['record']['server'] + " " 
     63                           + data['record']['server'] + " weight " 
     64                           + str(data['record']['weight']) + " maxcon " 
     65                           + str(data['record']['maxcon']) + "
    "
     66         if sub_record_info not in content_list:
     67             print("The record:{} doesn't exist, remove failed.".format(sub_record_info.strip()))
     68             return
     69         else:
     70             content_list.remove(sub_record_info)
     71         for i in range(backend_dict[data['backend']],len(content_list)-1):
     72             if content_list[i+1].startswith('backend '):
     73                 break
     74             else:
     75                 tmp_list.append(content_list[i+1])
     76         if 0 == len(tmp_list):
     77             content_list.remove(data['backend'])
     78         with open('haproxy.cfg',mode='w',encoding='utf-8') as wf:
     79             wf.writelines(content_list)
     80         print("The record:{} removed successfully.".format(sub_record_info.strip()))
     81 
     82 if __name__ == '__main__':
     83     info = '''
     84     1:查询
     85     2:增加
     86     3:删除
     87     4:退出程序
     88     '''
     89     menu_dict = {
     90         '1':select,
     91         '2':add,
     92         '3':remove,
     93         '4':exit,
     94     }
     95     while True:
     96         print(info)
     97         chioce = input('请输入操作序号>>> ').strip()
     98         if '4' == chioce: break
     99         if 0 == len(chioce) or chioce not in menu_dict:continue
    100         elif '1' == chioce:
    101             backend = input('请输入要查询的backend>>> ').strip()
    102             if 0 == len(backend):
    103                 print('Invalid input...')
    104             else:
    105                 select(backend)
    106         else:
    107             notice = 'Input Fomat: backend domain|server(domain/ip)|weight value|maxcon value'
    108             print(notice)
    109             data = input('请输入数据>>> ').strip()
    110             data_list = data.split('|')
    111             if 4 == len(data_list) and data_list[2].isdigit() and data_list[3].isdigit():
    112                 input_dict = {
    113                     'backend':data_list[0],
    114                     'record':{
    115                         'server':data_list[1],
    116                         'weight':int(data_list[2]),
    117                         'maxcon':int(data_list[3]),
    118                     },
    119                 }
    120                 menu_dict[chioce](input_dict)
    121             else:
    122                 print('Input invalid...')

     文件:

     1 frontend www
     2         bind *:80
     3         acl web hdr_beg(host)  10.207.252.45
     4         acl web1 hdr_beg(host)  10.207.252.46
     5         use_backend webserver if web
     6         use_backend web1server if web1
     7 
     8 backend www.oldboy1.org
     9         server 192.168.1.110 192.168.1.110 weight 10 maxcon 3007
    10         server 192.168.1.120 192.168.1.120 weight 10 maxcon 3009
    11         server 192.168.1.110 192.168.1.110 weight 10 maxcon 3009
    12 
    13 backend www.oldboy2.org
    14         server 192.168.1.130 192.168.1.130 weight 20 maxcon 3000
    15         server 192.168.1.131 192.168.1.131 weight 20 maxcon 3000
    16 backend www.qq.com
    17         server 3.3.3.3 3.3.3.3 weight 90 maxcon 100
    18         server 3.3.3.100 3.3.3.100 weight 90 maxcon 700
    19         server 8.8.8.9 8.8.8.9 weight 20 maxcon 200
    作者:Standby一生热爱名山大川、草原沙漠,还有妹子
    出处:http://www.cnblogs.com/standby/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    webstorm快捷键大全
    Js的reduce()方法
    利用 c# linq 实现多个数据库的联合查询
    微信小程序支付接入注意点
    ubuntu所有php扩展php-7.0扩展列表
    ubuntu 16.04 php 安装curl方法
    Ubuntu下配置Apache开启HTTPS
    Mac下如何用SSH连接远程Linux服务器及Linux一些常用操作命令,更新中.....
    Mac下如何用SSH连接远程Linux服务器
    C#的dapper使用
  • 原文地址:https://www.cnblogs.com/standby/p/6910613.html
Copyright © 2011-2022 走看看