• 第六章 Python 函数(二)


    第六章 Python 函数(二)

    一、一等公民:函数

     在 Python 中对象的优先等级:

          函数 ---> 类 ---> 模块 ---> 包

    1. 函数即"变量"

        在这里有必要强调一点:在 Python 中一切皆对象的概念;包括数字、字符串、元组、列表、字典和函数

        对就是,函数也是对象,还有列表、字典和元组中的一个元素都是对象。

        也就是,当你去定义一个对象是,每个对象都是有他的内存地址的

    >>> a = 'hlep'
    >>> id(a)
    140122643069728
    >>> for i in a:
    ...     id(i)
    ... 
    140122643280984
    140122643550816
    140122643550480
    140122643175720
    # 现在定义一个函数
    >>> def f1():
    ...     print('只有调用我时,此处才会被执行')
    ... 
    # 查看它的内存地址
    >>> id(f1)
    140122643775000
    >>>
    
    

       既然函数也是和其他的对象一样,那么它本身也应该具有某些对象的属性和特点。比如 定义一个列表:

    # 这里list1 是一个变量变量名
    >>> list1 = ['a','b','c']
    # 变量名也可以又被赋值给其他变量名
    >>> list2 = list1
    >>> list1 is list2
    True
    >>> id(list1)
    140122643092424
    >>> id(list2)
    140122643092424
    >>> 
    #  当然函数也可以这样操作
    >>> def f1():
    ...     print('当这个函数被调用时,此处代码才会被执行')
    ... 
    # 可以将此函数赋值给其他的变量名
    >>> func = f1
    >>> print(f1)
    <function f1 at 0x7f70d85d8510>
    >>> print(func)
    <function f1 at 0x7f70d85d8510>
    >>> func is f1
    True
    >>> 从以上信息可以看出 func 就是 f1,那么此时调用 func() 就是在调用f1()
    >>> func()
    当这个函数被调用时,此处代码才会被执行
    >>> 

      当定义一个函数,其实是执行了对一个变量名(即函数名)赋值的操作。

      

    >>> def f1():
    ...     print("其实这里的函数体,在定义函数时,在内存里就是一串字符串")
    ... 
    >>> 
    
    >>> # 在内存中是这样的:f1 = 'print("其实这里的函数体,在定义函数时,在内存里就是一串字 
    符串")'
    
    '''只有在调用时,python 会对这串字符串编译成字节码,再由 python 去解释器这些字节码,
     ... 解释字节码是,会先检查字节码中那些是符合 python 的语法,再跟进语法执行。'''

    2. 命名空间和作用域

     1 [root@localhost python3]# cat namespace.py 
     2 #!/usr/bin/env    python3
     3 # 这个脚本是用来展示命名空间和变量的作用域的
     4 x = 1
     5 print('主程序 x 的值:',x)
     6 print('主程序 x 的内存地址:',id(x))
     7 
     8 def f1():
     9     x = 10
    10     print('函数 x 的值:',x)
    11     print('函数 x 的内存地址:',id(x))
    12     
    13 f1()    
    14 [root@localhost python3]# python3 namespace.py 
    15 主程序 x 的值: 1
    16 主程序 x 的内存地址: 9220192
    17 函数 x 的值: 10
    18 函数 x 的内存地址: 9220480
    19 [root@localhost python3]#
    20 
    21 # 
    View Code

     

    二、高阶函数

      特点:

    • 1. 把一个函数的函数名当做实参传给另一个函数

        前面提到了,  函数即变量,定义一个函数,也就是定义一个变量而已。变量可以被当做参数来被函数使用,当然,函数也可以被当做参数被传递和使用

    # 定义一个函数,打印 数字 521
    >>> def answer():
     ...     print(521)
     ... 
    # 再定义一个函数,这个函数有个形参 func
    >>> def run_something(func):
    ...     func()                     # 调用被传进来的函数
    ... 
    # 执行run_something函数时,把 answer函数的函数名当做一个实参传给这个函数
    >>> run_something(answer)  
    521
    >>>
    
    # 传的时候可不是传 answer()  而是 answer 函数的本身  
    >>> def run_something(func):
    ...     print(func)
    ... 
    # 传的是 answer(),那么这个函数将会先运行,之后传进去的只是函数的执行的结果,这样, run_something 这个函数
    # 接收到的将是一个 None ,之后就会报错
    >>> run_something(answer())
    ok            # 函数先在解释器中运行了本身
    None          # 之后输出了返回值
    Traceback (most recent call last):   # 传递个使用它的函数时,传的是 None ,所以报错了
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 3, in run_something
    TypeError: 'NoneType' object is not callable
    >>>

        再来看另一例子:

     1 >>> def add_args(a,b):
     2 ...     print(a + b)
     3 ... 
     4 >>> def run_somthing_with_args(func,arg1,arg2):
     5 ...     func(arg1,arg2)
     6 ... 
     7 >>> run_somthing_with_args(add_args,5,6)
     8  11
     9 >>> 
    10 #   运行run_somthing_with_args(5,6,add_args)时:
    11     5,6被赋值给 arg1,arg2;add_args被赋值给了 func;
    12     而在函数 run_somthing_with_args 中,调用含参数的函数func(arg1,arg2),
    13     而在此时,函数func 也就是add_args,而这两个参数arg1,arg2也就传给了 a 和 b,
    14     即 a = arg1 = 5,b = arg2 = 6
    15     在这里同样可以用上 *args,**kwargs  的技巧
    16 >>> def sum_args(*args,**kwargs):
    17 ...     print(args,kwargs)
    18 ... 
    19 >>> def run_with_args(func,*args,**kwargs):
    20 ...     func(*args,**kwargs)
    21 ... 
    22 >>> run_with_args(sum_args,2,a=1)
    23 (2,) {'a': 1}
    24 >>> 
    • 2. 另一个函数返回值中包含一个函数的函数名

        函数可以返回任意数量的任何类型的数据,当然也包括某一个函数的本身

    >>> def sum_args(*args):
    ...     print(sum(args))
    ... 
    >>> def return_func(func):
    ...     return func
    ... 
    >>> return_func(sum_args)
    <function sum_args at 0x7f0eaeae0e18>   #可以看出执行函数,此时返回的只是一个对象,对象的名字就叫 sum_args
    >>> f1 = return_func(sum_args)  # 把这个对象赋值个一个变量名,即 f1 = sum_args
    >>> f1(7,8)     #调用f1(7,8)  也就是在调用 sum_args(7,8)
    15
    >>> 

    三、嵌套函数

      嵌套函数有时也叫做内部函数,就是在一个函数的内部再定义一个函数

    >>> def outer(a,b):
    ...         def inner(c,d):
    ...             return   c + d
    ...         return inner(a,b)
    ... 
    >>> outer(5,6)
    11
    >>> 
    
    # 来简单分析一下执行 outer(5,6)时的流程:
    1. 执行 outer(5,6), 将5和6 传入函数outer 即:a = 5, b = 6
    2. 在函数 outer 内部定义另一个函数 inner 即: inner = 'return c + b'
    3. 最后返回一个值,这个值就是函数 inner的结果,同时把变量 a 和 b 当做实参传给了 inner 函数,
       即:c = a = 5 , d = b = 6 
       在 inner 函数内部也有个返回值 c + d ,此时也就是 5 + 6
    4. 执行的结果就是 outer(5,6) = inner(5,6),结果就是 11
       

    四、闭包函数

        闭包函数是另一个函数动态生成的函数,并且可以储存和使用或者改变闭包函数外创建的变量的值

    >>> def outer(arg):
    ...     def inner():
    ...         return '我是内部的闭包函数,我在使用外部的变量:%s' % arg
    ...     return inner
    ... 
    >>> outer("Im's outer arg")
    <function outer.<locals>.inner at 0x7f0eaea35730>
    >>> f1 = outer("Im's outer arg")
    >>> f1()
    "我是内部的闭包函数,我在使用外部的变量:Im's outer arg"
    >>> 

    函数 inner 使用了其外部函数的参数(变量) arg ,并且外部函数返回的是函数 inner 本身,而不是调用函数 inner 和函数inner的返回值
    此时, inner函数就是一个闭包函数

    >>> f1
    <function outer.<locals>.inner at 0x7f0eaea35950>
    >>>

    五、装饰器

       装饰器中会会使用一下几个技巧

        ·   *args 和 ** kwargs

        ·   闭包

        ·   作为参数的函数

    • 1. 基本装饰器

    import time
    def inner():
        time.sleep(3)
        print('in then inner')
    
    
    def timer(func):
        def wraper():
            start_time = time.time()
            func()
            stop_time = time.time()
            print('func run time id %s' %(stop_time - start_time))
        return wraper
    
    decorator = timer(inner)   # 手工设置装饰器
    
    decorator()
    
    执行结果:
    in then inner
    func run time id 3.000171422958374
    
    # 上面是手工赋值的方式;当然Python不会这么low,已经给你制定了一个很好的方试,
    让你可以足够的装逼
    import time
    
    def timer(func):
        def wrapper():
            start_time = time.time()
            func()
            stop_time = time.time()
            print('func run time id %s' %(stop_time - start_time))
        return wrapper
    @timer
    #  这里的 @timer 就是Python提供的装逼技巧
    def inner(): time.sleep(3) print('in then inner') inner()

        装饰器做了两件事:

        1. 执行装饰器函数,并且同时把要装饰的函数名,当做实参传入。

        2. 返回一个在装饰器内部定义的函数名,即一个对象;并且这个返回值含有了两个东西:

          a.  内部函数本身的功能

          b.  被装饰的函数执行结果

        当使用装饰器时又做了两件事:

        1. 执行装饰器函数

        2. 把装饰器的返回值又重新赋值给被装饰的函数;即 inner = wrapper

    • 2. 装饰器执行流程

    • 3. 装饰器之传参

    • 4. 装饰器之返回值

    五、多层装饰器

    六、内置函数

    内置函数也叫内置方法,在 Python 已启动就加载到 Python 解释器里的。可以直接使用的一些函数。

    下图中就是 Python 中全部的内置函数

    值得注意的几个内置函数用法

    #compile
    f = open("函数递归.py")
    data =compile(f.read(),'','exec')
    exec(data)
    
    
    #print
    msg = "又回到最初的起点"
    f = open("tofile","w")
    print(msg,"记忆中你青涩的脸",sep="|",end="",file=f)
    
    
    # #slice
    # a = range(20)
    # pattern = slice(3,8,2)
    # for i in a[pattern]: #等于a[3:8:2]
    #     print(i)
    #
    #
    
    
    #memoryview
    #usage:
    #>>> memoryview(b'abcd')
    #<memory at 0x104069648>
    #在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存,
    import time
    for n in (100000, 200000, 300000, 400000):
        data = b'x'*n
        start = time.time()
        b = data
        while b:
            b = b[1:]
        print('bytes', n, time.time()-start)
    
    for n in (100000, 200000, 300000, 400000):
        data = b'x'*n
        start = time.time()
        b = memoryview(data)
        while b:
            b = b[1:]
        print('memoryview', n, time.time()-start)
    

    七、生成器

    八、迭代器

    九、软件目录开发规范

  • 相关阅读:
    【3.5】类和实例属性的查找顺序--mro查找
    【3.4】类变量和实例变量
    【3.3】isinstance和type的区别
    【3.2】抽象基类(abc模块)
    【3.1】鸭子类型和多态
    学习笔记 | 浅谈虚拟函数(Virtual Function)
    学习笔记 | Udacity CarND Term 1: Computer Vision and Deep Learning
    命令行 | File Compression in Linux
    Python: if else in a list comprehension
    Topic | Hyperparameter Optimization for Neural Networks
  • 原文地址:https://www.cnblogs.com/xiguatian/p/6392069.html
Copyright © 2020-2023  润新知