第十八-十九章 Functions and Generators

第十八章 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 3
1 2 3
1 2 3
Traceback (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 keywords
print(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 used
1 (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 keywords
1 (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 call
1 (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 default
1 (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 res

def lessthan(x, y): return x < y                # See also: lambda
def grtrthan(x, y): return x > y

print(minmax(lessthan, 4, 2, 1, 5, 6, 3))       # Self-test code
print(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 tot

L = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nesting
print(sumtree(L))                                # Prints 36

# Pathological cases
print(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 end

def 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 tot

L = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nesting
print(sumtree(L))                                # Prints 36

# Pathological cases
print(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 tot

L = [1, [2, [3, 4], 5], 6, [7, 8]]               # Arbitrary nesting
print(sumtree(L))                                # Prints 36

# Pathological cases
print(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 functions
for f in L:
    print(f(2)) # Prints 4, 8, 16
print(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 print
spam
toast
eggs

>>> showall = lambda x: [sys.stdout.write(line) for line in x]
>>> t = showall(('bright\n', 'side\n', 'of\n', 'life\n'))
bright
side
of
life
>>>



import sys
from tkinter import Button, mainloop # Tkinter in 2.X
x = 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**4
81
>>> 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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值