我是Python的新手,我正在尝试打印参数的默认值集。我的代码如下;
# Functions
def shoppingcart(item='computer', *price):
print item
for i in price:
print i
shoppingcart(100,200,300)
当我运行代码时,我得到的只是值100,200,300
。我期待computer,100,200,300
。我做错了什么?
修改
我如何在Python 2.7中实现这一目标?
修改
我将代码更新为
def shoppingcart(item='computer', *price):
print item
for i in price:
print i
shoppingcart(item='laptop', 100,200,300)
然而得到错误
答案 0 :(得分:6)
简单地说,只有在没有其他方法时才使用默认值。您有item=100
,其他2个值进入*price
。
在Python3中你可以写:
def shoppingcart(*prices, item='computer'):
print(item)
print(prices)
shoppingcart(100,200,300)
shoppingcart(100,200,300, item='moon')
在Python2中,你不能在*args
之后拥有默认参数,所以你必须找到另一种方法来调用你的函数。
答案 1 :(得分:3)
对于Python 2.x,您必须使用**
语法:
def shoppingcart(*prices, **kwargs):
item = kwargs.pop("item", "computer")
assert not kwargs, "This function only expects 'item' as keyword argument".
print(item)
print(prices)
然后你可以传递关键字参数:
shoppingcart(100,200,300, item='moon')
(他们总是需要在“位置”参数之后)
答案 2 :(得分:2)
你想做什么是不可能的。你永远不能用Python写这个:
shoppingcart(item='laptop', 100,200,300)
在2.x或3.x中,您将收到错误:
SyntaxError: non-keyword arg after keyword arg
首先,一点背景:
“关键字”参数类似于item='laptop'
,您可以在其中指定名称和值。 “位置”或“非关键字”参数类似于100
,您可以在其中指定值。无论何时调用函数,都必须在所有位置参数之后放置关键字args。因此,您可以撰写shoppingcart(100, 200, 300, item='laptop')
,但不能写shoppingcart(item='laptop', 100, 200, 300)
。
当您理解关键字参数的处理方式时,这会更有意义。让我们采用一个非常简单的案例,使用一组固定的参数而没有默认值,以使一切变得更容易:
def shoppingcart(item, price):
print item, price
无论我使用shoppingcart('laptop', 200)
,shoppingcart(price=200, item='laptop')
还是其他任何可能性,您都可以了解参数如何在函数体中item
和price
中到达。除了shoppingcart(price=200, 'laptop')
之外,Python无法分辨laptop
应该是什么 - 它不是第一个参数,它没有给出显式关键字item
,所以它不能是{ {1}}。但它也不能是item
,因为我已经得到了它。如果你仔细考虑,那么每当我尝试在位置参数之前传递关键字参数时,它就会遇到同样的问题。在更复杂的情况下,更难以理解为什么,但它甚至不能在最简单的情况下工作。
因此,Python将引发price
,甚至没有看到你的函数是如何定义的。所以没有办法改变你的功能定义来使这个工作;这是不可能的。
但如果你将SyntaxError: non-keyword arg after keyword arg
移到参数列表的末尾,那么我可以调用item
,一切都会好的,对吧?不幸的是,不,因为您使用shoppingcart(100, 200, 300, item='computer')
来吸收*args
,并且您无法在100, 200, 300
之后添加任何显式参数。事实证明,这种限制没有原则性的原因,所以他们在Python 3中取消了它 - 但如果你仍然使用2.7,你必须忍受它。但至少有一种解决方法。
解决这个问题的方法是使用*args
来吸收所有关键字参数并自己解析它们,就像使用**kwargs
来吸收所有位置参数一样。就像*args
获得带有位置参数的*args
一样,list
会获得**kwargs
,每个关键字参数的关键字都映射到其值。
所以:
dict
如果您希望>>> def shoppingcart(*args, **kwargs):
... print args, kwargs
>>> shoppingcart(100, 200, 300, item='laptop')
[100, 200, 300], {'item': 'laptop'}
是强制性的,只需按以下方式访问:
item
如果您希望它是可选的,使用默认值,则执行以下操作:
item = kwargs['item']
但是这里有一个问题:你只想接受一个可选的item = kwargs.get('item', 'computer')
参数,但现在你实际上接受了任何关键字参数。如果您使用简单的函数尝试此操作,则会出现错误:
item
使用>>> def simplefunc(a, b, c):
... print a, b, c
>>> simplefunc(1, 2, 3, 4)
TypeError: simplefunc() takes exactly 3 arguments (4 given)
>>> simplefunc(a=1, b=2, c=3, d=4, e=5)
TypeError: simplefunc() got an unexpected keyword argument 'd'
模拟此功能非常简单。请记住,它只是一个普通的**kwargs
,所以如果你在解析它们时取出预期的关键字,那么应该没有任何剩余 - 如果存在,则调用者传递了一个意外的关键字参数。如果你不想这样,你可以提出错误。你可以这样写:
dict
然而,有一个方便的捷径。 def shoppingcart(*prices, **kwargs):
for key in kwargs:
if key != 'item':
raise TypeError("shoppingcart() got unexpected keyword argument(s) '%s' % kwargs.keys()[0]`)
item = kwargs.get('item', 'computer')
print item, prices
方法的行为与dict.pop
类似,但除了将值返回给您之外,它还会将其从字典中删除。在您删除dict.get
(如果它存在)之后,如果还有剩余的内容,那就是错误。所以,你可以这样做:
item
除非您正在构建一个可重用的库,否则您可以使用比整个def shoppingcart(*args, **kwargs):
item = kwargs.pop('item', 'computer')
if kwargs: # Something else was in there besides item!
raise TypeError("shoppingcart() got unexpected keyword argument(s) '%s' % kwargs.keys()[0]`)
/ if
更简单的东西,而只需raise
;没有人会关心您获得assert not kwargs
而不是AssertionError
。这就是lqc解决方案正在做的事情。
总结一下,你写你的功能并不重要;它永远不会被称为你想要的方式。但是如果你愿意将TypeError
移到最后,你可以写它并以合理的方式调用它(即使它不像Python 3版本那么简单或可读)。
对于一些罕见的情况,还有其他方法可以去。例如,如果价格总是必须是数字,并且项目始终是字符串,则可以更改代码以执行以下操作:
item
现在,你可以这样做:
def shoppingcart(*prices):
if prices and isinstance(prices[0], basestring):
item = prices.pop(0)
else:
item = 'computer'
print item
for price in prices:
print price
这基本上是Python用来实现>>> shoppingcart(100, 200, 300)
computer
100
200
300
>>> shoppingcart('laptop', 100, 200, 300) # notice no `item=` here
laptop
100
200
300
的一种技巧,它在你的代码中偶尔会有用。然而,它使你的实现更加脆弱,使你的函数的行为对读者来说更不明显,并且通常只是感觉不到Pythonic。因此,几乎总是最好避免这种情况,只是让调用者使用真正的关键字参数,如果这是你想要的,并且必须限制它们必须在最后。