zoukankan      html  css  js  c++  java
  • 使用doctest单元测试方式培训讲解:Python函数基础

    # coding = utf-8
    
    '''
    函数声明:
    def name([arg,... arg = value,... *arg, **kwarg]):
        suite
    
    1. 当编译器遇到 def,会生成创建函数对象指令。
       也就是说 def 是执⾏行指令,⽽不仅仅是个语法关键字。
       可以在任何地⽅方动态创建函数对象。
    2. 可以使用默认参数、可变参数和关键字参数
            arg = value 是默认参数
            *args是可变参数,args接收的是一个tuple;
            **kwargs是关键字参数,kwargs接收的是一个dict。
    
    lambda函数
    不同于⽤用 def 定义复杂函数,lambda 只能是有返回值的简单的表达式。使⽤用赋值语句会引发语法 错误,可以考虑⽤用函数代替。
    '''
    
    '''
    *****************************************************
    1. 函数创建
       函数是第一类对象,可作为其他函数的实参或返回值。
       函数总是有返回值。就算没有 return,默认也会返回 None。
    *****************************************************
    '''
    def test1(name):
        '''
    
        >>> test1('a').__name__ # 查看函数返回函数的名字
        'a'
    
        >>> test1('b').__name__ # 查看函数返回函数的名字
        'b'
    
        >>> test1('a')()        # 调用函数返回的函数
        call function a
    
        >>> print(test1('c'))   # 调用函数,返回2个值:整型和字符串
        (0, 'test')
        '''
        if name == "a":
            def a():
                print('call function a')
            return a
        elif name == "b":
            def b(): pass
            return b
        else:
            return 0, 'test'
    
    '''
    *************************************************************
    2. 参数
       2.1 函数的传参方式灵活多变,可按位置顺序传参,也可不关⼼顺序⽤命名实参。
    *************************************************************
    '''
    def test21(a, b):
        '''
    
        >>> test21(1,2)      # 位置参数
        1 2
    
        >>> test21(b=3,a=4)  # 命名参数
        4 3
        '''
        print(a, b)
    
    '''
    *************************************************************
       2.2 ⽀持参数默认值。不过要⼩⼼,
           默认值对象在创建函数时生成,所有调用都使⽤同⼀对象。
           如果该默认值是可变类型,那么就如同 C 静态局部变量。
    *************************************************************
    '''
    def test22(x, lst=[]):
        '''
        >>> test22(1)
        [1]
    
        >>> test22(2)   # 保持了上次调⽤用状态。
        [1, 2]
    
        >>> test22(3, [])   # 显式提供实参,不使⽤用默认值。
        [3]
    
        >>> test22(3)   # 再次使⽤用默认值,会继续使用默认的列表对象
        [1, 2, 3]
    
        '''
    
        lst.append(x)
        return lst
    
    '''
    *************************************************************
       2.3 默认参数后⾯不能有其他位置参数,除非是变参。
       SyntaxError: def test23(a, b=1, c): pass
    
       2.4 用 *args 收集 "多余" 的位置参数,**kwargs 收集 "额外" 的命名参数。
           这两个名字只是惯例,可 ⾃自由命名。
           *args是可变参数,args接收的是一个tuple;
           **kwargs是关键字参数,kwargs接收的是一个dict。
    *************************************************************
    '''
    def test24(a, b=1, *args, **kwargs):
        '''
    
        >>> test24(0)
        0
        1
        ()
        {}
    
        >>> test24(0,2,3,4)
        0
        2
        (3, 4)
        {}
    
        >>> test24(0,2,3,4,x=5)
        0
        2
        (3, 4)
        {'x': 5}
    
        # 可 "展开" 序列类型和字典,将全部元素当做多个实参使⽤用。如不展开的话,那仅是单个实参对象。
        >>> test24(*range(5), **{'x': 10, 'y': 11})
        0
        1
        (2, 3, 4)
        {'x': 10, 'y': 11}
    
        >>> test24(range(5))
        range(0, 5)
        1
        ()
        {}
    
        # 单个 "*" 展开序列类型,或者仅是字典的主键列表。
        # "**" 展开字典键值对。但如果没有变参收集, 展开后多余的参数将引发异常。
        >>> p = dict(a=20,b=21)
    
        >>> test24(p)
        {'a': 20, 'b': 21}
        1
        ()
        {}
    
        >>> test24(*p)  # 仅展开 keys(),test("a"、"b")
        a
        b
        ()
        {}
    
        >>> test24(**p)  # 展开 items(),test(a = 1, b = 2)。
        20
        21
        ()
        {}
        '''
    
        print(a)
        print(b)
        print(args)
        print(kwargs)
    
    '''
    *************************************************************
    3. 作用域
       3.1 函数形参和内部变量都存储在 locals 名字空间中。
    *************************************************************
    '''
    def test31(a, b=1):
        '''
    
        >>> test31(100)
        {'s': 'Hello Python', 'b': 1, 'a': 100}
    
        '''
    
        s = 'Hello Python'
        print(locals())
    
    '''
    *************************************************************
        3.2 除⾮使用 global、nonlocal 特别声明,
          否则,在函数内部使用赋值语句,总是在 locals 名字空间中 新建一个对象关联。
          注意:"赋值" 是指名字指向新的对象,⽽⾮通过名字改变对象状态。
    
          名字查找顺序: locals -> enclosing function -> globals -> __builtins__
        • locals: 函数内部名字空间,包括局部变量和形参。
        • enclosing function: 外部嵌套函数的名字空间。
        • globals: 函数定义所在模块的名字空间。
        • __builtins__: 内置模块的名字空间。
    
          如果不修改全局变量也可以不使用global关键字。
          Python3 提供了 nonlocal 关键字,用来修改外部 嵌套函数名字空间, python2.7 没有。
          nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。
    *************************************************************
    '''
    x, y = 1, 2  # 在模块级别直接定义的全局变量
    
    def test321():
        global x    # 引用全局变量
        x = 11
        y = 21      # 这里的 y 是局部变量
        global z    # 在函数内部定义一个全局变量,而没有在模块级别定义
        z = 3
    
        print(' in test321(): x=%d; y=%d; z=%d' % (x, y, z))
    
    def test322():
        print(' in test322(): x=%d; y=%d ; z=%d' % (x, y, z))    # 直接访问所有全局变量,包括变量z
    
    # 测试
    print('        out 1: x=%d; y=%d;  z=undefine' % (x, y))
    test321()
    test322()
    print('        out 2: x=%d; y=%d ; z=%d' % (x, y, z))
    
    
    '''
    *************************************************************
    3.3 闭包
        闭包(closure)是函数式编程的重要的语法结构。
        闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。
    *************************************************************
    '''
    
    def lineConfig(a,b):
        '''
        这个例子中,函数line与环境变量a,b构 成闭包。
        在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,
        这样我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。
        我们只需要变换参数a,b,就可以获得不同的直线表达函数。
        由此,我们可以看到,闭包也具有提高代码可复用性的作用。
    
        >>> y1 = lineConfig(1, 1)   # 定义直线 y = x + 1
        >>> p1 = y1(2)              # 计算y坐标,获取x=2时y1的值
        >>> print(p1)
        3
    
        >>> lstPoint = [y1(x) for x in range(3)] # 计算y坐标列表
        >>> print(lstPoint)
        [1, 2, 3]
    
        >>> y2 = lineConfig(4, 5)   # 定义直线 y = 4x + 5
        >>> p2 = y2(x=2)            # 计算y坐标,获取x=2时y2的值
        >>> print(p2)
        13
        '''
    
        def line(x):
            return a*x + b
    
        return line
    
    
    def newCounter(i=0):
        '''
        两个独立的计数器
        >>> c1 = newCounter()
        >>> c2 = newCounter(2)
        >>> print(c1(),c1(),c1())
        1 2 3
    
        >>> print(c2(),c2(),c2())
        3 4 5
    
        '''
    
        def counter():
            nonlocal i
            i = i + 1
            return i
        return counter
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod(verbose=True)
    

      

  • 相关阅读:
    POJ 1469 COURSES 二分图最大匹配
    POJ 1325 Machine Schedule 二分图最大匹配
    USACO Humble Numbers DP?
    SGU 194 Reactor Cooling 带容量上下限制的网络流
    POJ 3084 Panic Room 求最小割
    ZOJ 2587 Unique Attack 判断最小割是否唯一
    Poj 1815 Friendship 枚举+求最小割
    POJ 3308 Paratroopers 最小点权覆盖 求最小割
    1227. Rally Championship
    Etaoin Shrdlu
  • 原文地址:https://www.cnblogs.com/atsats/p/7747552.html
Copyright © 2011-2022 走看看