Apa yang dilakukan ** (bintang ganda / tanda bintang) dan * (tanda bintang / bintang) untuk parameter?

2352

Dalam definisi metode berikut, untuk apa *dan **lakukan param2?

def foo(param1, *param2):
def bar(param1, **param2):
Todd
sumber
4
lihat juga stackoverflow.com/questions/6967632/…
Aaron Hall
Lihat juga stackoverflow.com/questions/14301967/... untuk tanda bintang kosong
naught101
24
Pertanyaan ini adalah target duplikat yang sangat populer, tetapi sayangnya itu sering digunakan secara tidak benar. Ingatlah bahwa pertanyaan ini menanyakan tentang mendefinisikan fungsi dengan varargs ( def func(*args)). Untuk pertanyaan yang menanyakan apa artinya dalam panggilan fungsi ( func(*[1,2])) lihat di sini . Untuk pertanyaan yang menanyakan cara membuka paket argumen lihat di sini . Untuk pertanyaan yang menanyakan apa *artinya dalam literal ( [*[1, 2]]) lihat di sini .
Aran-Fey
Anda dapat mempelajari tentang penggunaannya dalam definisi fungsi dan panggilan fungsi di sini: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Jawaban:

2238

The *argsdan **kwargsmerupakan idiom umum untuk memungkinkan sejumlah argumen untuk fungsi seperti yang dijelaskan dalam bagian ini lebih lanjut tentang mendefinisikan fungsi dalam dokumentasi Python.

Ini *argsakan memberi Anda semua parameter fungsi sebagai tuple :

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

Itu **kwargsakan memberi Anda semua argumen kata kunci kecuali yang terkait dengan parameter formal sebagai kamus.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# age 27
# name one

Kedua idiom dapat dicampur dengan argumen normal untuk memungkinkan serangkaian argumen tetap dan beberapa variabel:

def foo(kind, *args, **kwargs):
   pass

Mungkin juga untuk menggunakan ini sebaliknya:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Penggunaan lain dari *lidiom adalah untuk membongkar daftar argumen saat memanggil suatu fungsi.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

Dalam Python 3 dimungkinkan untuk digunakan *ldi sisi kiri tugas ( Extended Iterable Unpacking ), meskipun itu memberikan daftar alih-alih tupel dalam konteks ini:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Juga Python 3 menambahkan semantik baru (lihat PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Fungsi semacam itu hanya menerima 3 argumen posisi, dan semuanya setelahnya *hanya dapat diteruskan sebagai argumen kata kunci.

Peter Hoffmann
sumber
9
Output [6] dalam urutan terbalik. nama satu usia 27
thanos.a
54
@ thanos.a Python dicts, secara semantik digunakan untuk melewati argumen kata kunci, dipesan secara sewenang-wenang. Namun, dalam Python 3.6, argumen kata kunci dijamin untuk mengingat urutan penyisipan. "Urutan elemen **kwargssekarang sesuai dengan urutan argumen kata kunci diteruskan ke fungsi." - docs.python.org/3/whatsnew/3.6.html Bahkan, semua dikt dalam CPython 3.6 akan mengingat urutan penyisipan sebagai detail implementasi, ini menjadi standar dalam Python 3.7.
Aaron Hall
13
Sangat tepat, bersih, dan mudah dimengerti. Saya menghargai bahwa Anda mencatat bahwa ini adalah "operator pembongkaran", sehingga saya dapat membedakan dari melewatinya dengan referensi dalam C. +1
bballdave025
Bagaimana cara menguji fungsi terakhir dengan PEP 3102? Saya menyebutnya dengan func (1,2,3, name = "me", age = 10) dan itu melempar pengecualian:got an unexpected keyword argument 'name'
Kok How Teh
@KokHowTeh Anda harus meneruskan kwarg yang dinamai dalam fungsi: func (1, 2, 3, kwarg1 = 'me', kwarg2 = 10)
John Aaron
622

Perlu juga dicatat bahwa Anda dapat menggunakan *dan **saat memanggil fungsi juga. Ini adalah jalan pintas yang memungkinkan Anda untuk menyampaikan banyak argumen ke suatu fungsi secara langsung menggunakan daftar / tuple atau kamus. Misalnya, jika Anda memiliki fungsi berikut:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Anda dapat melakukan hal-hal seperti:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Catatan: Kunci-kunci di dalam mydictharus diberi nama persis seperti parameter fungsi foo. Kalau tidak, ia akan melempar TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'
Lorin Hochstein
sumber
175

Tunggal * berarti bahwa dapat ada sejumlah argumen posisi ekstra. foo()dapat dipanggil seperti foo(1,2,3,4,5). Di dalam tubuh foo () param2 adalah urutan yang mengandung 2-5.

Double ** berarti ada sejumlah parameter bernama tambahan. bar()dapat dipanggil seperti bar(1, a=2, b=3). Di dalam body bar () param2 adalah kamus yang berisi {'a': 2, 'b': 3}

Dengan kode berikut:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

outputnya adalah

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}
nickd
sumber
5
Mungkin diperlukan contoh tambahan dengan foobar(param1, *param2, **param3)untuk melengkapi jawaban ini.
Aniket Thakur
1
@AniketThakur menambahkan bagian yang tersisa di sini .
Raj
148

Apa yang dilakukan **(bintang ganda) dan *(bintang) lakukan untuk parameter

Mereka memungkinkan fungsi didefinisikan untuk menerima dan bagi pengguna untuk memberikan sejumlah argumen, posisi ( *) dan kata kunci ( **).

Mendefinisikan Fungsi

*argsmemungkinkan sejumlah argumen posisi opsional (parameter), yang akan ditugaskan ke sebuah tuple bernama args.

**kwargsmemungkinkan sejumlah argumen kata kunci opsional (parameter), yang akan berada dalam nama yang ditentukan kwargs.

Anda dapat (dan harus) memilih nama yang sesuai, tetapi jika maksudnya argumennya adalah semantik non-spesifik, argsdan kwargsmerupakan nama standar.

Ekspansi, Melewati sejumlah argumen

Anda juga dapat menggunakan *argsdan **kwargsmengirimkan parameter dari daftar (atau setiap iterable) dan dicts (atau pemetaan apa pun), masing-masing.

Fungsi menerima parameter tidak harus tahu bahwa mereka sedang diperluas.

Misalnya, xrange Python 2 tidak secara eksplisit berharap *args, tetapi karena dibutuhkan 3 bilangan bulat sebagai argumen:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

Sebagai contoh lain, kita dapat menggunakan ekspansi dict di str.format:

>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Baru di Python 3: Menentukan fungsi dengan argumen hanya kata kunci

Anda dapat memiliki argumen hanya kata kunci setelah *args- misalnya, di sini, kwarg2harus diberikan sebagai argumen kata kunci - tidak secara posisi:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Pemakaian:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

Juga, *dapat digunakan dengan sendirinya untuk menunjukkan bahwa hanya mengikuti kata kunci argumen, tanpa memungkinkan untuk argumen posisi tak terbatas.

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Di sini, kwarg2sekali lagi harus berupa argumen kata kunci yang dinamai secara eksplisit:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

Dan kami tidak dapat lagi menerima argumen posisi yang tidak terbatas karena kami tidak memiliki *args*:

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Sekali lagi, lebih sederhana, di sini kita perlu kwargdiberi nama, bukan secara posisi:

def bar(*, kwarg=None): 
    return kwarg

Dalam contoh ini, kita melihat bahwa jika kita mencoba untuk melewati kwargposisi, kita mendapatkan kesalahan:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

Kami harus secara eksplisit melewatkan kwargparameter sebagai argumen kata kunci.

>>> bar(kwarg='kwarg')
'kwarg'

Demo yang kompatibel dengan Python 2

*args(biasanya dikatakan "star-args") dan **kwargs(bintang dapat tersirat dengan mengatakan "kwargs", tetapi secara eksplisit dengan "kwarg bintang ganda") adalah idiom umum dari Python untuk menggunakan *dan **notasi. Nama-nama variabel spesifik ini tidak diperlukan (misalnya Anda bisa menggunakan *foosdan **bars), tetapi keberangkatan dari konvensi cenderung membuat marah sesama pembuat kode Python Anda.

Kita biasanya menggunakan ini ketika kita tidak tahu apa fungsi kita akan menerima atau berapa banyak argumen yang mungkin kita lewati, dan kadang-kadang bahkan ketika penamaan setiap variabel secara terpisah akan menjadi sangat berantakan dan berlebihan (tetapi ini adalah kasus di mana biasanya eksplisit adalah lebih baik daripada implisit).

Contoh 1

Fungsi berikut menjelaskan bagaimana mereka dapat digunakan, dan menunjukkan perilaku. Perhatikan bargumen bernama akan dikonsumsi oleh argumen posisi kedua sebelum:

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and 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))

Kami dapat memeriksa bantuan online untuk tanda tangan fungsi, dengan help(foo), yang memberi tahu kami

foo(a, b=10, *args, **kwargs)

Mari kita panggil fungsi ini dengan foo(1, 2, 3, 4, e=5, f=6, g=7)

yang mencetak:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

Contoh 2

Kami juga dapat menyebutnya menggunakan fungsi lain, yang hanya kami sediakan 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) cetakan:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Contoh 3: penggunaan praktis dalam dekorator

OK, jadi mungkin kita belum melihat utilitasnya. Jadi bayangkan Anda memiliki beberapa fungsi dengan kode redundan sebelum dan / atau setelah kode pembeda. Fungsi bernama berikut ini hanya pseudo-code untuk tujuan ilustrasi.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

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

Kami mungkin dapat menangani hal ini secara berbeda, tetapi kami dapat mengekstraksi redundansi dengan dekorator, dan contoh kami di bawah ini menunjukkan bagaimana *argsdan **kwargsbisa sangat berguna:

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

Dan sekarang setiap fungsi yang dibungkus dapat ditulis lebih ringkas, karena kami telah memperhitungkan redundansi:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

Dan oleh anjak keluar kode kita, yang *argsdan **kwargsmemungkinkan kita untuk melakukan, kita mengurangi baris kode, lebih mudah dibaca dan rawatan, dan memiliki lokasi kanonik tunggal untuk logika dalam program kami. Jika kita perlu mengubah bagian mana pun dari struktur ini, kita memiliki satu tempat untuk membuat setiap perubahan.

Aaron Hall
sumber
48

Mari kita pahami dulu apa itu argumen posisi dan argumen kata kunci. Di bawah ini adalah contoh definisi fungsi dengan argumen Posisional.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Jadi ini adalah definisi fungsi dengan argumen posisi. Anda dapat menyebutnya dengan argumen kata kunci / bernama:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Sekarang mari kita pelajari contoh definisi fungsi dengan argumen kata kunci :

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

Anda dapat memanggil fungsi ini dengan argumen posisional juga:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Jadi kita sekarang tahu definisi fungsi dengan argumen posisi dan kata kunci.

Sekarang mari kita pelajari operator '*' dan operator '**'.

Harap dicatat operator ini dapat digunakan di 2 area:

a) panggilan fungsi

b) definisi fungsi

Penggunaan operator '*' dan operator '**' dalam panggilan fungsi.

Mari kita langsung ke contoh dan mendiskusikannya.

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 '*' operator
sum(*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.

Jadi ingatlah

ketika operator '*' atau '**' digunakan dalam panggilan fungsi -

Operator '*' membongkar struktur data seperti daftar atau tuple ke argumen yang diperlukan oleh definisi fungsi.

Operator '**' membongkar kamus ke dalam argumen yang diperlukan oleh definisi fungsi.

Sekarang mari kita pelajari penggunaan operator '*' dalam definisi fungsi . Contoh:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

Dalam definisi fungsi , operator '*' mengemas argumen yang diterima menjadi tuple.

Sekarang mari kita lihat contoh '**' yang digunakan dalam definisi fungsi:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

Dalam definisi fungsi, operator '**' mengemas argumen yang diterima ke dalam kamus.

Jadi ingat:

Dalam suatu fungsi panggil '*' membongkar struktur data tuple atau daftar ke argumen posisi atau kata kunci yang akan diterima oleh definisi fungsi.

Dalam suatu fungsi panggil '**' membongkar struktur data kamus ke dalam argumen posisi atau kata kunci yang akan diterima oleh definisi fungsi.

Dalam definisi fungsi , '*' mengemas argumen posisi menjadi tuple.

Dalam definisi fungsi , '**' mengemas argumen kata kunci ke dalam kamus.

Karan Ahuja
sumber
Sangat bersih, selangkah demi selangkah dan mudah diikuti penjelasannya!
Aleksandar
Terima kasih, terus upvotes datang. [Juga untuk catatan lebih lanjut dari saya, saya di @mrtechmaker di twitter]
Karan Ahuja
32

Tabel ini berguna untuk menggunakan *dan **dalam konstruksi fungsi dan panggilan fungsi :

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Ini benar-benar hanya berfungsi untuk meringkas jawaban Lorin Hochstein, tetapi saya merasa itu membantu.

Terkait: penggunaan untuk operator bintang / percikan telah diperluas di Python 3

Brad Solomon
sumber
22

*dan **memiliki penggunaan khusus dalam daftar argumen fungsi. * menyiratkan bahwa argumen adalah daftar dan **menyiratkan bahwa argumen adalah kamus. Ini memungkinkan fungsi untuk mengambil sejumlah argumen yang berubah-ubah

ronak
sumber
17

Bagi Anda yang belajar melalui contoh!

  1. Tujuannya * adalah untuk memberi Anda kemampuan untuk mendefinisikan suatu fungsi yang dapat mengambil sejumlah argumen sewenang-wenang yang disediakan sebagai daftar (misalnya f(*myList)).
  2. Tujuannya **adalah untuk memberi Anda kemampuan untuk memberi makan argumen fungsi dengan menyediakan kamus (misalnya f(**{'x' : 1, 'y' : 2})).

Mari kita tunjukkan ini dengan mendefinisikan fungsi yang mengambil dua variabel yang normal x, ydan dapat menerima lebih argumen sebagai myArgs, dan dapat menerima bahkan lebih argumen sebagai myKW. Nanti, kami akan menunjukkan cara memberi makan ymenggunakan myArgDict.

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 purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("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 myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("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   = {}
# ----------------------------------------------------------------------

Peringatan

  1. ** khusus disediakan untuk kamus.
  2. Penugasan argumen non-opsional terjadi terlebih dahulu.
  3. Anda tidak dapat menggunakan argumen non-opsional dua kali.
  4. Jika berlaku, **harus datang setelahnya *, selalu.
Miladiouss
sumber
14

Dari dokumentasi Python:

Jika ada lebih banyak argumen posisi daripada ada slot parameter formal, pengecualian TypeError dinaikkan, kecuali ada parameter formal menggunakan sintaks "* pengenal"; dalam hal ini, parameter formal menerima tuple yang berisi argumen posisi berlebih (atau tuple kosong jika tidak ada argumen posisi berlebih).

Jika ada argumen kata kunci yang tidak sesuai dengan nama parameter formal, pengecualian TypeError dinaikkan, kecuali ada parameter formal menggunakan sintaks "** identifier"; dalam hal ini, parameter formal tersebut menerima kamus yang berisi argumen kata kunci berlebih (menggunakan kata kunci sebagai kunci dan nilai argumen sebagai nilai yang sesuai), atau kamus kosong (baru) jika tidak ada argumen kata kunci berlebih.

Chris Upchurch
sumber
10

* berarti menerima argumen variabel sebagai tuple

** berarti menerima argumen variabel sebagai kamus

Digunakan seperti berikut:

1) tunggal *

def foo(*args):
    for arg in args:
        print(arg)

foo("two", 3)

Keluaran:

two
3

2) Sekarang **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])

bar(dic1="two", dic2=3)

Keluaran:

dic1 two
dic2 3
ishandutta2007
sumber
8

Saya ingin memberi contoh yang belum disebutkan orang lain

* juga dapat membongkar generator

Contoh dari Dokumen Python3

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x akan menjadi [1, 2, 3], unzip_y akan menjadi [4, 5, 6]

Zip () menerima beberapa arg iretable, dan mengembalikan generator.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
Lochu'an Chang
sumber
7

Dalam Python 3.5, Anda juga dapat menggunakan sintaks ini di list, dict, tuple, dan setmenampilkan (juga kadang-kadang disebut literal). Lihat PEP 488: Generalisasi Pembongkaran Tambahan .

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

Ini juga memungkinkan beberapa iterables dibongkar dalam satu panggilan fungsi.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(Terima kasih kepada mgilson untuk tautan PEP.)

leewz
sumber
1
Saya tidak yakin ini merupakan pelanggaran "hanya ada satu cara untuk melakukannya". Tidak ada cara lain untuk menginisialisasi daftar / tuple dari beberapa iterables - Anda saat ini perlu untuk mengaitkannya menjadi satu iterable yang tidak selalu nyaman. Anda bisa membaca tentang rasionalnya di PEP-0448 . Juga, ini bukan fitur python3.x, ini fitur python3.5 + :-).
mgilson
@ Mcgson, itu akan menjelaskan mengapa itu tidak disebutkan sebelumnya.
leewz
6

Selain panggilan fungsi, * args dan ** kwargs berguna dalam hierarki kelas dan juga menghindari keharusan menulis __init__metode dengan Python. Penggunaan serupa dapat dilihat dalam kerangka kerja seperti kode Django.

Sebagai contoh,

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])

Subkelas kemudian bisa

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

Subkelas kemudian akan dipakai sebagai

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

Juga, subclass dengan atribut baru yang hanya masuk akal untuk instance subclass dapat memanggil kelas Basis __init__untuk menurunkan beban pengaturan atribut. Ini dilakukan melalui * args dan ** kwargs. kwargs terutama digunakan agar kode dapat dibaca menggunakan argumen bernama. Sebagai contoh,

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)

yang dapat dinegatifkan sebagai

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

Kode lengkapnya ada di sini

quiet_penguin
sumber
1
1. Pada dasarnya init adalah metode, jadi (dalam konteks ini) tidak terlalu berbeda. 2. Gunakan # untuk komentar, bukan "" ", yang hanya menandai string literal. 3. Menggunakan super harus menjadi cara yang disukai, terutama untuk contoh Anda dengan pewarisan multi-level.
0xc0de
4

Membangun jawaban nickd ...

def foo(param1, *param2):
    print(param1)
    print(param2)


def bar(param1, **param2):
    print(param1)
    print(param2)


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Keluaran:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

1
(2, 3, 4)
{'s': 5}

Pada dasarnya, sejumlah argumen posisi dapat menggunakan * args dan argumen bernama apa pun (atau kwarg alias argumen kata kunci) dapat menggunakan ** kwargs.

Raj
sumber
3

*argsdan **kwargs: memungkinkan Anda meneruskan sejumlah variabel argumen ke suatu fungsi.

*args: digunakan untuk mengirim daftar argumen panjang variabel non-kata kunci ke fungsi:

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')

Akan menghasilkan:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

**kwargsmemungkinkan Anda untuk meneruskan panjang variabel variabel yang di-kata kunci ke suatu fungsi. Anda harus menggunakan **kwargsjika Anda ingin menangani argumen bernama dalam suatu fungsi.

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")  

Akan menghasilkan:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
Harvey
sumber
2

Contoh ini akan membantu Anda mengingat *args, **kwargsdan bahkan superdan warisan dalam Python sekaligus.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(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_param
        super(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 # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1
Thanhtang
sumber
1

Contoh yang baik menggunakan keduanya dalam suatu fungsi adalah:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}
amir jj
sumber
1

TL; DR

Di bawah ini adalah 6 kasus penggunaan berbeda untuk *dan **dalam pemrograman python:

  1. Untuk menerima sejumlah argumen posisi menggunakan *args: def foo(*args): pass , di sini foomenerima sejumlah argumen posisional, yaitu, panggilan berikut adalah valid foo(1),foo(1, 'bar')
  2. Untuk menerima sejumlah argumen kata kunci menggunakan **kwargs: def foo(**kwargs): pass , di sini 'foo' menerima sejumlah argumen kata kunci, yaitu, panggilan berikut adalah valid foo(name='Tom'),foo(name='Tom', age=33)
  3. Untuk menerima sejumlah argumen posisional dan kata kunci menggunakan *args, **kwargs: def foo(*args, **kwargs): pass , di sini foomenerima sejumlah argumen posisional dan kata kunci, yaitu, panggilan berikut adalah valid foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Untuk menegakkan kata kunci hanya argumen menggunakan *: def foo(pos1, pos2, *, kwarg1): pass , di sini *berarti bahwa foo hanya menerima argumen kata kunci setelah pos2, maka foo(1, 2, 3)menimbulkan TypeError tapi foo(1, 2, kwarg1=3)ok.
  5. Untuk tidak menyatakan minat lebih lanjut pada argumen lebih banyak menggunakan *_(Catatan: ini hanya konvensi): def foo(bar, baz, *_): pass berarti (dengan konvensi) foohanya menggunakan bardan bazargumen dalam bekerja dan akan mengabaikan yang lain.
  6. Untuk tidak menyatakan minat lebih lanjut pada lebih banyak argumen kata kunci menggunakan \**_(Catatan: ini hanya konvensi): def foo(bar, baz, **_): pass berarti (dengan konvensi) foohanya menggunakan bardan bazargumen dalam kerjanya dan akan mengabaikan yang lain.

BONUS: Dari python 3.8 dan seterusnya, seseorang dapat menggunakan /definisi fungsi untuk menegakkan hanya parameter posisi. Dalam contoh berikut, parameter a dan b adalah hanya-posisi , sedangkan c atau d dapat berupa posisi atau kata kunci, dan e atau f diharuskan menjadi kata kunci:

def f(a, b, /, c, d, *, e, f):
    pass
Meysam Sadeghi
sumber
0

TL; DR

Itu paket argumen yang dilewatkan ke fungsi ke listdan dictmasing - masing di dalam fungsi tubuh Ketika Anda mendefinisikan tanda tangan fungsi seperti ini:

def func(*args, **kwds):
    # do stuff

dapat dipanggil dengan sejumlah argumen dan argumen kata kunci. Argumen non-kata kunci dimasukkan ke dalam daftar yang disebut argsdi dalam badan fungsi dan argumen kata kunci dimasukkan ke dalam dict yang disebut kwdsdi dalam bagian fungsi.

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

sekarang di dalam tubuh fungsi, ketika fungsi dipanggil, ada dua variabel lokal, argsyang merupakan daftar yang memiliki nilai ["this", "is a list of", "non-keyword", "arguments"]dan kwdsyang dictmemiliki nilai{"keyword" : "ligma", "options" : [1,2,3]}


Ini juga bekerja secara terbalik, yaitu dari sisi penelepon. misalnya jika Anda memiliki fungsi yang didefinisikan sebagai:

def f(a, b, c, d=1, e=10):
    # do stuff

Anda dapat memanggilnya dengan membongkar iterables atau pemetaan yang Anda miliki dalam lingkup panggilan:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)
RBF06
sumber
0

Konteks

  • python 3.x
  • membongkar dengan **
  • gunakan dengan pemformatan string

Gunakan dengan pemformatan string

Selain jawaban di utas ini, berikut adalah detail lain yang tidak disebutkan di tempat lain. Ini memperluas jawaban dari Brad Solomon

Membongkar dengan **juga berguna saat menggunakan python str.format.

Ini agak mirip dengan apa yang dapat Anda lakukan dengan python f-strings f-string tetapi dengan overhead tambahan mendeklarasikan dict untuk menampung variabel (f-string tidak memerlukan dict).

Contoh cepat

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.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.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])
dreftymac
sumber
-2
  • def foo(param1, *param2): adalah metode dapat menerima jumlah nilai sewenang-wenang untuk *param2 ,
  • def bar(param1, **param2): adalah metode dapat menerima jumlah nilai sewenang-wenang dengan kunci untuk *param2
  • param1 adalah parameter sederhana.

Misalnya, sintaks untuk mengimplementasikan varargs di Java sebagai berikut:

accessModifier methodName(datatype arg) {
    // method body
}
Premraj
sumber