• python 函数的调用 和执行 小知识


    1.符号表

    执行一个函数会引入一个用于函数的局部变量的新符号表。

    更确切地说,

    函数中的所有的赋值都是将值存储在局部符号表;

    而变量引用首先查找局部符号表,

    然后是上层函数的局部符号表,

    然后是全局符号表,

    最后是内置名字表。

    因此,在函数内部全局变量不能直接赋值(除非在一个global语句中命名),虽然可以引用它们。

    2.传值

    函数调用的实际参数在函数被调用时引入被调函数的局部符号表;

    因此,

    参数的传递使用传值调用

    (这里的值始终是对象的引用,不是对象的值)。

    一个函数调用另一个函数时,

    会为该调用创建一个新的局部符号表。

    函数定义会在当前符号表内引入函数名。

    函数名对应值的类型是解释器可识别的用户自定义函数。

    此值可以分配给另一个名称,

    然后也可作为函数。

    这是通用的重命名机制:

    传参:默认值在定义域中的函数定义的时候计算

    重要的警告:

    默认值只计算一次。

    这使得默认值是列表、字典或大部分类的实例时会有所不同。

    例如,

    下面的函数在后续调用过程中会累积传给它的参数:

    def f(a, L=[]):
        L.append(a)
        return L
    
    print f(1)
    print f(2)
    print f(3)
    

    这将会打印

    [1]
    [1, 2]
    [1, 2, 3]
    

    如果你不想默认值在随后的调用中共享,

    可以像这样编写函数:

    def f(a, L=None):
        if L is None:
            L = []
        L.append(a)
        return L

    当最后一个形参以**name形式出现时,

    它接收一个字典(见映射类型 — 字典),

    该字典包含了所有未出现在形式参数列表中的关键字参数。

    它还可能与*name形式的参数(在下一小节中所述)组合使用,

    *name接收一个包含所有没有出现在形式参数列表中的位置参数元组。

    (*name必须出现在**name之前。)

    例如,

    如果我们定义这样的函数:

    def cheeseshop(kind, *arguments, **keywords):
        print "-- Do you have any", kind, "?"
        print "-- I'm sorry, we're all out of", kind
        for arg in arguments:
            print arg
        print "-" * 40
        keys = sorted(keywords.keys())
        for kw in keys:
            print kw, ":", keywords[kw]
    

    它可以这样调用:

    cheeseshop("Limburger", "It's very runny, sir.",
               "It's really very, VERY runny, sir.",
               shopkeeper='Michael Palin',
               client="John Cleese",
               sketch="Cheese Shop Sketch")
    

    当然它会打印:

    -- Do you have any Limburger ?
    -- I'm sorry, we're all out of Limburger
    It's very runny, sir.
    It's really very, VERY runny, sir.
    ----------------------------------------
    client : John Cleese
    shopkeeper : Michael Palin
    sketch : Cheese Shop Sketch

    注意在打印关键字参数之前,

    通过对关键字字典 keys() 方法的结果进行排序,

    生成了关键字参数名的列表;

    如果不这样做,

    打印出来的参数的顺序是未定义的。

     

     

    3.过程和函数的区别

    如果你使用过其他语言,你可能会反对说:

    fib不是一个函数,而是一个过程(子程序),

    因为它并不返回任何值。

    事实上,没有return语句的函数也返回一个值,尽管是一个很无聊的值。

    此值被称为None(它是一个内置的名称)。

    如果 None只是唯一的输出,解释器通常不会打印出来。

    如果你真的想看到这个值,可以使用print 语句。

    4.参数拆分

    参数列表的分拆

    当传递的参数已经是一个列表或元组时,

    情况与之前相反,

    你要分拆这些参数,

    因为函数调用要求独立的位置参数。

    例如,

    内置的range()函数期望单独的start和stop参数。

    如果它们不是独立的,

    函数调用时使用 *-操作符将参数从列表或元组中分拆开来:

    >>>
    >>> range(3, 6)             # normal call with separate arguments
    [3, 4, 5]
    >>> args = [3, 6]
    >>> range(*args)            # call with arguments unpacked from a list
    [3, 4, 5]
    

    以同样的方式,可以用**-操作符让字典传递关键字参数:

    >>>
    >>> def parrot(voltage, state='a stiff', action='voom'):
    ...     print "-- This parrot wouldn't", action,
    ...     print "if you put", voltage, "volts through it.",
    ...     print "E's", state, "!"
    ...
    >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
    >>> parrot(**d)
    -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

    5.lambda匿名小函数

    可以使用lambda关键字创建小的匿名函数。

    下面这个函数返回它的两个参数的和:

    lambda a, b: a + b

    Lambda 函数可以用于任何需要函数对象的地方。

    在语法上,它们被局限于只能有一个单独的表达式。

    在语义上,他们只是普通函数定义的语法糖。

    像嵌套的函数定义,lambda 函数可以从包含范围引用变量:

    def make_incrementor(n):
    ...     return lambda x: x + n
    ...
    >>> f = make_incrementor(42)
    >>> f(0)
    42
    >>> f(1)
    43
    

    上面的示例使用 lambda 表达式返回一个函数。

    另一个用途是将一个小函数作为参数传递:

    >>>
    >>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
    >>> pairs.sort(key=lambda pair: pair[1])
    >>> pairs
    [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
    

     

     

    6.文档字符串

    第一行永远应该是对象用途的简短、精确的总述。为了简单起见,不应该明确的陈述对象的名字或类型,因为这些信息可以从别的途径了解到(除非这个名字碰巧就是描述这个函数操作的动词)。这一行应该以大写字母开头,并以句号结尾。

    如果在文档字符串中有更多的行,第二行应该是空白,在视觉上把摘要与剩余的描述分离开来。以下各行应该是一段或多段描述对象的调用约定、 其副作用等。

    Python 解释器不会从多行的文档字符串中去除缩进,所以必要的时候处理文档字符串的工具应当自己清除缩进。这通过使用以下约定可以达到。第一行 之后 的第一个非空行字符串确定整个文档字符串的缩进的量。(我们不用第一行是因为它通常紧靠着字符串起始的引号,其缩进格式不明晰。)所有行起始的等于缩进量的空格都将被过滤掉。不应该发生缩进较少的行,但如果他们发生,应去除所有其前导空白。留白的长度应当等于扩展制表符的宽度(正常是 8 个空格)。

    这里是一个多行文档字符串的示例:

    >>>
    >>> def my_function():
    ...     """Do nothing, but document it.
    ...
    ...     No, really, it doesn't do anything.
    ...     """
    ...     pass
    ...
    >>> print my_function.__doc__
    Do nothing, but document it.
    
        No, really, it doesn't do anything.
    

     

     
  • 相关阅读:
    bzoj1045: [HAOI2008] 糖果传递(数论)
    bzoj1083: [SCOI2005]繁忙的都市(最小生成树)
    bzoj1079: [SCOI2008]着色方案(DP)
    BZOJ2467 [中山市选2010]生成树
    BZOJ4766 文艺计算姬
    BZOJ4894 天赋
    BZOJ2560 串珠子
    [SDOI2014]重建
    BZOJ3622 已经没有什么好害怕的了
    [SDOI2016]储能表
  • 原文地址:https://www.cnblogs.com/hackerl/p/4782685.html
Copyright © 2020-2023  润新知