2

我是 Python 新手,正在尝试打印为参数设置的默认值。我的代码如下;

# Functions

def shoppingcart(item='computer', *price):
    print item
    for i in price:
        print i

shoppingcart(100,200,300)

当我运行代码时,我得到的只是 values 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)

但是得到错误

在此处输入图像描述

4

3 回答 3

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所以你必须找到另一种方法来调用你的函数。

于 2012-12-09T23:59:32.280 回答
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')

(他们总是需要在“位置”参数之后)

于 2012-12-10T01:08:51.813 回答
2

你想做的事是不可能的。你永远不能用 Python 写这个:

shoppingcart(item='laptop', 100,200,300)

在 2.x 或 3.x 中,您将收到一个错误:

SyntaxError: non-keyword arg after keyword arg

首先,一点背景:

“关键字”参数类似于item='laptop',您可以在其中指定名称和值。“位置”或“非关键字”参数类似于100,您只需在其中指定值。每当您调用函数时,都必须将关键字 args 放在所有位置 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,所以它不可能是item. 但它也不能是price,因为我已经得到了。而且,如果您仔细考虑一下,每当我尝试在位置参数之前传递关键字参数时,都会遇到同样的问题。在更复杂的情况下,很难看出原因,但在最简单的情况下它甚至不起作用。

因此,Python 将引发 a SyntaxError: non-keyword arg after keyword arg,甚至无需查看您的函数是如何定义的。所以没有办法改变你的函数定义来使它工作;这是不可能的。

但是如果你移到item参数列表的末尾,那么我可以打电话shoppingcart(100, 200, 300, item='computer'),一切都会好起来的,对吧?不幸的是,不,因为您正在使用*args吸收100, 200, 300,并且您不能在 . 之后放置任何显式参数*args。事实证明,这个限制没有原则性的理由,所以他们在 Python 3 中取消了它——但如果你仍在使用 2.7,你必须忍受它。但至少有一个解决方法。

解决这个问题的方法是用来**kwargs吸收所有关键字参数并自己解析它们,就像你用来*args吸收所有位置参数一样。就像使用位置参数为*args您提供 a一样,为您提供每个关键字参数的关键字映射到其值的关键字。list**kwargsdict

所以:

>>> 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而不是一个TypeError。这就是lqc的解决方案正在做的事情。

回顾一下,如何编写函数并不重要。它永远不能被称为你想要的方式。但如果你愿意item走到最后,你既可以写也可以用合理的方式调用它(即使它不像 Python 3 版本那么简单或可读)。

对于一些罕见的情况,还有其他方法可以走。例如,如果价格总是必须是数字,而商品总是字符串,你可以改变你的代码来做这样的事情:

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

现在,您可以这样做:

>>> shoppingcart(100, 200, 300)
computer
100
200
300
>>> shoppingcart('laptop', 100, 200, 300) # notice no `item=` here
laptop
100
200
300

这基本上是 Python 用来实现的一种技巧slice(start=None, stop, step=None),它在您的代码中非常有用。但是,它使您的实现更加脆弱,使您的函数的行为对读者来说不太明显,并且通常不会让人感觉像 Python。所以,几乎总是最好避免这种情况,如果你想要的话,只让调用者使用真正的关键字参数,限制它们必须在最后。

于 2012-12-10T01:41:03.667 回答