def foo(a, b=10, *args, **kwargs):'''this function takes required argument a, not required keyword argument band any number of unknown positional arguments and keyword arguments after'''print('a is a required argument, and its value is {0}'.format(a))print('b not required, its default value is 10, actual value: {0}'.format(b))# we can inspect the unknown arguments we were passed:# - args:print('args is of type {0} and length {1}'.format(type(args), len(args)))for arg in args:print('unknown arg: {0}'.format(arg))# - kwargs:print('kwargs is of type {0} and length {1}'.format(type(kwargs),len(kwargs)))for kw, arg in kwargs.items():print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))# But we don't have to know anything about them# to pass them to other functions.print('Args or kwargs can be passed without knowing what they are.')# max can take two or more positional args: max(a, b, c...)print('e.g. max(a, b, *args) \n{0}'.format(max(a, b, *args)))kweg = 'dict({0})'.format( # named args same as unknown kwargs', '.join('{k}={v}'.format(k=k, v=v)for k, v in sorted(kwargs.items())))print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(dict(**kwargs), kweg=kweg))
我们可以查看函数签名的在线帮助,使用help(foo),它告诉我们
foo(a, b=10, *args, **kwargs)
让我们用foo(1, 2, 3, 4, e=5, f=6, g=7)调用这个函数
其中打印:
a is a required argument, and its value is 1b not required, its default value is 10, actual value: 2args is of type <type 'tuple'> and length 2unknown arg: 3unknown arg: 4kwargs is of type <type 'dict'> and length 3unknown kwarg - kw: e, arg: 5unknown kwarg - kw: g, arg: 7unknown kwarg - kw: f, arg: 6Args or kwargs can be passed without knowing what they are.e.g. max(a, b, *args)4e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns:{'e': 5, 'g': 7, 'f': 6}
例2
我们也可以使用另一个函数调用它,我们只提供a:
def bar(a):b, c, d, e, f = 2, 3, 4, 5, 6# dumping every local variable into foo as a keyword argument# by expanding the locals dict:foo(**locals())
bar(100)打印:
a is a required argument, and its value is 100b not required, its default value is 10, actual value: 2args is of type <type 'tuple'> and length 0kwargs is of type <type 'dict'> and length 4unknown kwarg - kw: c, arg: 3unknown kwarg - kw: e, arg: 5unknown kwarg - kw: d, arg: 4unknown kwarg - kw: f, arg: 6Args or kwargs can be passed without knowing what they are.e.g. max(a, b, *args)100e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns:{'c': 3, 'e': 5, 'd': 4, 'f': 6}
def foo(a, b, c, d=0, e=100):# imagine this is much more code than a simple function callpreprocess()differentiating_process_foo(a,b,c,d,e)# imagine this is much more code than a simple function callpostprocess()
def bar(a, b, c=None, d=0, e=100, f=None):preprocess()differentiating_process_bar(a,b,c,d,e,f)postprocess()
def baz(a, b, c, d, e, f):... and so on
def decorator(function):'''function to wrap other functions with a pre- and postprocess'''@functools.wraps(function) # applies module, name, and docstring to wrapperdef wrapper(*args, **kwargs):# again, imagine this is complicated, but we only write it once!preprocess()function(*args, **kwargs)postprocess()return wrapper
def __init__(self, *args, **kwargs):for attribute_name, value in zip(self._expected_attributes, args):setattr(self, attribute_name, value)if kwargs.has_key(attribute_name):kwargs.pop(attribute_name)
for attribute_name in kwargs.viewkeys():setattr(self, attribute_name, kwargs[attribute_name])
一个子类可以是
class RetailItem(Item):_expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']
class FoodItem(RetailItem):_expected_attributes = RetailItem._expected_attributes + ['expiry_date']
class ElectronicAccessories(RetailItem):_expected_attributes = RetailItem._expected_attributes + ['specifications']# Depend on args and kwargs to populate the data as needed.def __init__(self, specifications = None, *args, **kwargs):self.specifications = specifications # Rest of attributes will make sense to parent class.super(ElectronicAccessories, self).__init__(*args, **kwargs)
def sum(a,b): #receive args from function calls as sum(1,2) or sum(a=1,b=2)print(a+b)
my_tuple = (1,2)my_list = [1,2]my_dict = {'a':1,'b':2}
# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operatorsum(*my_tuple) # becomes same as sum(1,2) after unpacking my_tuple with '*'sum(*my_list) # becomes same as sum(1,2) after unpacking my_list with '*'sum(**my_dict) # becomes same as sum(a=1,b=2) after unpacking by '**'
# output is 3 in all three calls to sum function.
所以记住
当在函数调用中使用“*”或“**”运算符时-
'*'运算符将数据结构(例如列表或元组)解压缩为函数定义所需的参数。
'**'运算符将字典解压缩为函数定义所需的参数。
现在让我们研究函数定义中的'*'运算符用法。示例:
def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))sum = 0for a in args:sum+=aprint(sum)
sum(1,2,3,4) #positional args sent to function sum#output:10
在函数定义中,“*”运算符将接收到的参数打包成一个元组。
现在让我们看看函数定义中使用的'**'示例:
def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})sum=0for k,v in args.items():sum+=vprint(sum)
sum(a=1,b=2,c=3,d=4) #positional args sent to function sum
class base(object):def __init__(self, base_param):self.base_param = base_param
class child1(base): # inherited from base classdef __init__(self, child_param, *args) # *args for non-keyword argsself.child_param = child_paramsuper(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg
class child2(base):def __init__(self, child_param, **kwargs):self.child_param = child_paramsuper(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg
c1 = child1(1,0)c2 = child2(1,base_param=0)print c1.base_param # 0print c1.child_param # 1print c2.base_param # 0print c2.child_param # 1
def args(normal_arg, *argv):print("normal argument:", normal_arg)
for arg in argv:print("Argument in list of arguments from *argv:", arg)
args('animals', 'fish', 'duck', 'bird')
将产生:
normal argument: animalsArgument in list of arguments from *argv: fishArgument in list of arguments from *argv: duckArgument in list of arguments from *argv: bird
def who(**kwargs):if kwargs is not None:for key, value in kwargs.items():print("Your %s is %s." % (key, value))
who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")
将产生:
Your name is Nikola.Your last_name is Tesla.Your birthday is 7.10.1856.Your birthplace is Croatia.
def f(x, y, *myArgs, **myKW):print("# x = {}".format(x))print("# y = {}".format(y))print("# myArgs = {}".format(myArgs))print("# myKW = {}".format(myKW))print("# ----------------------------------------------------------------------")
# Define a list for demonstration purposesmyList = ["Left", "Right", "Up", "Down"]# Define a dictionary for demonstration purposesmyDict = {"Wubba": "lubba", "Dub": "dub"}# Define a dictionary to feed ymyArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}
# The 1st elem of myList feeds yf("myEx", *myList, **myDict)# x = myEx# y = Left# myArgs = ('Right', 'Up', 'Down')# myKW = {'Wubba': 'lubba', 'Dub': 'dub'}# ----------------------------------------------------------------------
# y is matched and fed first# The rest of myArgDict becomes additional arguments feeding myKWf("myEx", **myArgDict)# x = myEx# y = Why?# myArgs = ()# myKW = {'y0': 'Why not?', 'q': 'Here is a cue!'}# ----------------------------------------------------------------------
# The rest of myArgDict becomes additional arguments feeding myArgsf("myEx", *myArgDict)# x = myEx# y = y# myArgs = ('y0', 'q')# myKW = {}# ----------------------------------------------------------------------
# Feed extra arguments manually and append even more from my listf("myEx", 4, 42, 420, *myList, *myDict, **myDict)# x = myEx# y = 4# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')# myKW = {'Wubba': 'lubba', 'Dub': 'dub'}# ----------------------------------------------------------------------
# Without the stars, the entire provided list and dict become x, and y:f(myList, myDict)# x = ['Left', 'Right', 'Up', 'Down']# y = {'Wubba': 'lubba', 'Dub': 'dub'}# myArgs = ()# myKW = {}# ----------------------------------------------------------------------
## init varsddvars = dict()ddcalc = dict()passddvars['fname'] = 'Huomer'ddvars['lname'] = 'Huimpson'ddvars['motto'] = 'I love donuts!'ddvars['age'] = 33passddcalc['ydiff'] = 5ddcalc['ycalc'] = ddvars['age'] + ddcalc['ydiff']passvdemo = []
## ********************## single unpack supported in py 2.7vdemo.append('''Hello {fname} {lname}!
Today you are {age} years old!
We love your motto "{motto}" and we agree with you!'''.format(**ddvars))pass
## ********************## multiple unpack supported in py 3.xvdemo.append('''Hello {fname} {lname}!
In {ydiff} years you will be {ycalc} years old!'''.format(**ddvars,**ddcalc))pass
## ********************print(vdemo[-1])
sum = lambda x, y, z: x + y + zsum(1,2,3) # sum 3 items
sum([1,2,3]) # error, needs 3 items, not 1 list
x = [1,2,3][0]y = [1,2,3][1]z = [1,2,3][2]sum(x,y,z) # ok
sum(*[1,2,3]) # ok, 1 list becomes 3 items
def print_all(*args, **kwargs):print(args) # print any number of arguments like: "print_all("foo", "bar")"print(kwargs.get("to_print")) # print the value of the keyworded argument "to_print"
# example:print_all("Hello", "World", to_print="!")# will print:"""('Hello', 'World')!"""