2

私は 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)

ただし、エラーが発生します

ここに画像の説明を入力

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 を配置する必要があります。つまり、 と書くことはできますが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いないため、item. priceしかし、私はすでにそれを持っているので、それもできません。よく考えてみると、位置引数の前にキーワード引数を渡そうとするたびに、同じ問題が発生します。より複雑なケースでは、その理由を理解するのが難しくなりますが、最も単純なケースでも機能しません。

そのため、Python は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するのと同じように、各キーワード引数のキーワードをその値にマップして を取得します。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ます。の代わりにが取得されても、誰も気にしません。それが、lqc のソリューションが行っていることです。raiseassert not kwargsAssertionErrorTypeError

要約すると、関数をどのように記述するかは問題ではありません。思い通りに呼び出すことはできません。しかし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)であり、コードで非常に役立つ場合があります。ただし、実装がはるかに壊れやすくなり、関数の動作が読者にとってわかりにくくなり、一般的に Pythonic とは感じられなくなります。したがって、ほとんどの場合、これを回避し、必要に応じて呼び出し元に実際のキーワード引数を使用させ、最後に来なければならないという制限を設けることが最善です。

于 2012-12-10T01:41:03.667 に答える