第十八-十九章 Functions and Generators

来源:互联网 发布:网络电影 编辑:程序博客网 时间:2024/06/04 18:27

第十八章 Arguments

1.Argument-Passing Basics

  • Arguments are passed by automatically assigning objects to local variable names.
  • Assigning to argument names inside a function does not affect the caller.
  • Changing a mutable object argument in a function may impact the caller.

Argument Matching Basics:

  • Positionals: matched from left to right
  • Keywords: matched by argument name
  • Defaults: specify values for optional arguments that aren’t passed
  • Varargs collecting: collect arbitrarily many positional or keyword arguments
  • Varargs unpacking: pass arbitrarily many positional or keyword arguments
  • Keyword-only arguments: arguments that must be passed by name


The Gritty Details:

  • In a function call, arguments must appear in this order: any positional arguments
    (value); followed by a combination of any keyword arguments (name=value) and
    the *iterable form; followed by the **dict form.
  • In a function header, arguments must appear in this order: any normal arguments
    (name); followed by any default arguments (name=value); followed by the *name (or
    * in 3.X) form; followed by any name or name=value keyword-only arguments (in
    3.X); followed by the **name form.

参数匹配:

  • Assign nonkeyword arguments by position
  • Assign keyword arguments by matching names.
  • Assign extra nonkeyword arguments to *name tuple.
  • Assign extra keyword arguments to **name dictionary.
  • Assign default values to unassigned arguments in header.

def f(a,b,c):    print(a,b,c)f(1,2,3)f(c=3,b=2,a=1)f(1,c=3,b=2)f(3,a=1,b=2)# f(b=3,c=4,1)   SyntaxError: non-keyword arg after keyword arg 
>>> ================================ RESTART ================================>>> 1 2 31 2 31 2 3Traceback (most recent call last):  File "D:\test.py", line 10, in <module>    f(3,a=1,b=2)TypeError: f() got multiple values for argument 'a'

Arbitrary Arguments Examples:

Headers: Collecting arguments

>>> def f(*args): print(args) #collects unmatched positional arguments into a tuple>>> f()()>>> f(1)(1,)>>> f(1, 2, 3, 4)(1, 2, 3, 4)>>> def f(**args): print(args) #works for keyword arguments,collects them into a new dictionary>>> f(){}>>> f(a=1, b=2){'a': 1, 'b': 2}>>> def f(a, *pargs, **kargs): print(a, pargs, kargs)>>> f(1, 2, 3, x=1, y=2)1 (2, 3) {'y': 2, 'x': 1}
Calls: Unpacking arguments

注意:one star means positionals, and two applies to keywords.


Python 3.X Keyword-Only Arguments

>>> def kwonly(a, *b, c):   #参数c只能用Keyword传参        print(a, b, c)>>> kwonly(1, 2, c=3)1 (2,) 3>>> kwonly(a=1, c=3)1 () 3>>> kwonly(1, 2, 3)TypeError: kwonly() missing 1 required keyword-only argument: 'c'


>>> def kwonly(a, *, b, c):  #does not accept a variable-length argument list but still expects all arguments following the * to be passed as keywordsprint(a, b, c)>>> kwonly(1, c=3, b=2)1 2 3>>> kwonly(c=3, b=2, a=1)1 2 3>>> kwonly(1, 2, 3)TypeError: kwonly() takes 1 positional argument but 3 were given>>> kwonly(1)TypeError: kwonly() missing 2 required keyword-only arguments: 'b' and 'c'


Ordering rules:

keyword-only arguments must be specified after a single star, not two

>>> def kwonly(a, **pargs, b, c):SyntaxError: invalid syntax>>> def kwonly(a, **, b, c):SyntaxError: invalid syntax>>> def f(a, *b, **d, c=6): print(a, b, c, d) # Keyword-only before **!SyntaxError: invalid syntax>>> def f(a, *b, c=6, **d): print(a, b, c, d) # Collect args in header>>> f(1, 2, 3, x=4, y=5) # Default used1 (2, 3) 6 {'y': 5, 'x': 4}>>> f(1, 2, 3, x=4, y=5, c=7) # Override default       注意与下面对比1 (2, 3) 7 {'y': 5, 'x': 4}>>> f(1, 2, 3, c=7, x=4, y=5) # Anywhere in keywords1 (2, 3) 7 {'y': 5, 'x': 4}>>> def f(a, c=6, *b, **d): print(a, b, c, d) # c is not keyword-only here!>>> f(1, 2, 3, x=4)1 (3,) 2 {'x': 4}

function calls: when keyword-only arguments are passed, they must appear before a **args form.

keyword-only argument can be coded either before or after the *args, though, and may be included in **args:

>>> def f(a, *b, c=6, **d): print(a, b, c, d) # KW-only between * and **>>> f(1, *(2, 3), **dict(x=4, y=5)) # Unpack args at call1 (2, 3) 6 {'y': 5, 'x': 4}>>> f(1, *(2, 3), **dict(x=4, y=5), c=7) # Keywords before **args!SyntaxError: invalid syntax>>> f(1, *(2, 3), c=7, **dict(x=4, y=5)) # Override default1 (2, 3) 7 {'y': 5, 'x': 4}>>> f(1, c=7, *(2, 3), **dict(x=4, y=5)) # After or before *1 (2, 3) 7 {'y': 5, 'x': 4}>>> f(1, *(2, 3), **dict(x=4, y=5, c=7)) # Keyword-only in **  也可在**中1 (2, 3) 7 {'y': 5, 'x': 4}


def minmax(test, *args):    res = args[0]    for arg in args[1:]:        if test(arg, res):            res = arg    return resdef lessthan(x, y): return x < y                # See also: lambdadef grtrthan(x, y): return x > yprint(minmax(lessthan, 4, 2, 1, 5, 6, 3))       # Self-test codeprint(minmax(grtrthan, 4, 2, 1, 5, 6, 3))

def sumtree(L):    tot = 0    for x in L:                                  # For each item at this level        if not isinstance(x, list):            tot += x                             # Add numbers directly        else:            tot += sumtree(x)                    # Recur for sublists    return totL = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nestingprint(sumtree(L))                                # Prints 36# Pathological casesprint(sumtree([1, [2, [3, [4, [5]]]]]))          # Prints 15 (right-heavy)print(sumtree([[[[[1], 2], 3], 4], 5]))          # Prints 15 (left-heavy)

# breadth-first by items: add to enddef sumtree(L):                                  # Breadth-first, explicit queue    tot = 0    items = list(L)                              # Start with copy of top level    while items:        trace(items)        front = items.pop(0)                     # Fetch/delete front item        if not isinstance(front, list):            tot += front                         # Add numbers directly            visit(front)        else:            items.extend(front)                  # <== Append all in nested list    return totL = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nestingprint(sumtree(L))                                # Prints 36# Pathological casesprint(sumtree([1, [2, [3, [4, [5]]]]]))          # Prints 15 (right-heavy)print(sumtree([[[[[1], 2], 3], 4], 5]))          # Prints 15 (left-heavy)print('-'*40)# depth-first by items: add to front (like recursive calls version)def sumtree(L):                                  # Depth-first, explicit stack    tot = 0    items = list(L)                              # Start with copy of top level    while items:        trace(items)        front = items.pop(0)                     # Fetch/delete front item        if not isinstance(front, list):            tot += front                         # Add numbers directly            visit(front)        else:            items[:0] = front                    # <== Prepend all in nested list    return totL = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nestingprint(sumtree(L))                                # Prints 36# Pathological casesprint(sumtree([1, [2, [3, [4, [5]]]]]))          # Prints 15 (right-heavy)print(sumtree([[[[[1], 2], 3], 4], 5]))          # Prints 15 (left-heavy)print('-'*40)


Function Objects: Attributes and Annotations:

annotations work only in def statements, not lambda expressions

def func(a: 'spam', b: (1, 10), c: float) -> int:    return a + b + c>>> func.__annotations__{'return': <class 'int'>, 'c': <class 'float'>, 'a': 'spam', 'b': (1, 10)}>>> def func(a: 'spam' = 4, b: (1, 10) = 5, c: float = 6) -> int:    #使用默认值        return a + b + c>>> def func(a:'spam'=4, b:(1,10)=5, c:float=6)->int: #空格可有可无        return a + b + c

Anonymous Functions: lambda:

lambda Basics:lambda argument1, argument2,... argumentN : expression using arguments

  • lambda is an expression, not a statement.
  • lambda’s body is a single expression, not a block of statements.

>>> def func(x, y, z): return x + y + z>>> func(2, 3, 4)9>>> f = lambda x, y, z: x + y + z    #  f is assigned the function object the lambda expression creates>>> f(2, 3, 4)9
lambda expressions introduce a local scope much like a nested def, which automatically
sees names in enclosing functions, the module, and the built-in scope (via the
LEGB rule,

L = [lambda x: x ** 2, # Inline function definition     lambda x: x ** 3,     lambda x: x ** 4] # A list of three callable functionsfor f in L:    print(f(2)) # Prints 4, 8, 16print(L[0](3)) # Prints 9

lambda内使用循环时,方法一使用map,方法二 list comprehension expressions

>>> import sys>>> showall = lambda x: list(map(sys.stdout.write, x)) # 3.X: must use list>>> t = showall(['spam\n', 'toast\n', 'eggs\n']) # 3.X: can use printspamtoasteggs>>> showall = lambda x: [sys.stdout.write(line) for line in x]>>> t = showall(('bright\n', 'side\n', 'of\n', 'life\n'))brightsideoflife>>>


import sysfrom tkinter import Button, mainloop # Tkinter in 2.Xx = Button(text='Press me',command=(lambda:sys.stdout.write('Spam\n'))) # 3.X: print()x.pack()mainloop() # This may be optional in console mode



Mapping Functions over Iterables: map

>>> counters = [1, 2, 3, 4]>>> def inc(x): return x + 10 # Function to be run>>> list(map(inc, counters)) # Collect results[11, 12, 13, 14]>>> list(map((lambda x: x + 3), counters)) # Function expression[4, 5, 6, 7]>>> pow(3, 4) # 3**481>>> list(map(pow, [1, 2, 3], [2, 3, 4])) # 1**2, 2**3, 3**4[1, 8, 81]
Selecting Items in Iterables: filter
>>> list(filter((lambda x: x > 0), range(−5, 5))) # An iterable in 3.X[1, 2, 3, 4]


Combining Items in Iterables: reduce

>>> from functools import reduce # Import in 3.X, not in 2.X>>> reduce((lambda x, y: x + y), [1, 2, 3, 4])10>>> reduce((lambda x, y: x * y), [1, 2, 3, 4])24




0 0
原创粉丝点击