为什么Python函数不打印默认值?

时间:2012-12-09 23:56:28

标签: python python-2.7

我是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)

然而得到错误

enter image description here

3 个答案:

答案 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')还是其他任何可能性,您都可以了解参数如何在函数体中itemprice中到达。除了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。因此,几乎总是最好避免这种情况,只是让调用者使用真正的关键字参数,如果这是你想要的,并且必须限制它们必须在最后。