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


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

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

1574
2017-08-31 15:04


asal


Jawaban:


Itu *args dan **kwargs adalah idiom umum untuk mengizinkan sejumlah argumen acak ke fungsi seperti yang dijelaskan di bagian lebih lanjut tentang mendefinisikan fungsi dalam dokumentasi Python.

Itu *args akan memberi Anda semua parameter fungsi sebagai tupel:

In [1]: def foo(*args):
   ...:     for a in args:
   ...:         print a
   ...:         
   ...:         

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

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

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

In [6]: bar(name='one', age=27)
age 27
name one

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

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

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

In [9]: def foo(bar, lee):
   ...:     print bar, lee
   ...:     
   ...:     

In [10]: l = [1,2]

In [11]: foo(*l)
1 2

Dengan Python 3 dimungkinkan untuk digunakan *l di sisi kiri penugasan (Perpanjangan Iterable Unpacking), meskipun memberikan daftar, bukannya 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 seperti itu hanya menerima 3 argumen posisional, dan semuanya sesudahnya * hanya dapat dilewatkan sebagai argumen kata kunci.


1550
2017-08-31 15:17



Ini juga perlu diperhatikan yang dapat Anda gunakan * dan ** saat memanggil fungsi juga. Ini adalah cara pintas yang memungkinkan Anda untuk mengirimkan beberapa argumen ke fungsi secara langsung menggunakan daftar / tupel 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: Tombol-tombol masuk mydict harus diberi nama persis seperti parameter fungsi foo. Kalau tidak maka akan melempar a 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'

448
2017-08-31 15:47



Single * berarti bahwa bisa ada sejumlah argumen posisi tambahan. foo() dapat dipanggil seperti foo(1,2,3,4,5). Dalam tubuh foo () param2 adalah urutan yang mengandung 2-5.

Ganda ** berarti bisa ada sejumlah parameter bernama tambahan. bar() dapat dipanggil seperti bar(1, a=2, b=3). Di badan 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)

hasilnya adalah

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

128
2017-08-31 15:20



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

Mereka memungkinkan fungsi yang harus didefinisikan untuk diterima dan untuk pengguna untuk lulus sejumlah argumen, posisi (*) dan kata kunci (**).

Menentukan Fungsi

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

**kwargs memungkinkan untuk sejumlah argumen kata kunci opsional (parameter), yang akan diberi nama kwargs.

Anda dapat (dan seharusnya) memilih nama yang sesuai, tetapi jika tujuannya adalah untuk argumen menjadi semantik non-spesifik, args dan kwargs adalah nama standar.

Ekspansi, Melewati sejumlah argumen

Anda juga bisa menggunakan *args dan **kwargs untuk meneruskan parameter dari daftar (atau setiap iterable) dan dicts (atau pemetaan apa pun), masing-masing.

Fungsi yang menerima parameter tidak harus mengetahui bahwa mereka sedang diperluas.

Sebagai contoh, xrange Python 2 tidak secara eksplisit diharapkan *args, tetapi karena membutuhkan 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 bisa menggunakan ekspansi dict str.format:

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

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

Kamu bisa memiliki hanya argumen kata kunci setelah *args - misalnya, di sini, kwarg2 harus diberikan sebagai argumen kata kunci - tidak secara posisional:

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 kata kunci hanya mengikuti argumen, tanpa membolehkan argumen posisi yang tidak terbatas.

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

Sini, kwarg2 lagi harus berupa argumen kata kunci yang bernama secara eksplisit:

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

Dan kita tidak bisa lagi menerima argumen posisi yang tidak terbatas karena kita tidak punya *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 sederhananya, di sini kita membutuhkan kwarg diberi nama, bukan secara posisi:

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

Dalam contoh ini, kita melihat bahwa jika kita mencoba untuk lulus kwarg secara posisional, 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 lulus kwarg parameter sebagai argumen kata kunci.

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

Python 2 demo yang kompatibel

*args (Biasanya kata "bintang-args") dan **kwargs (Bintang dapat disiratkan dengan mengatakan "kwargs", tetapi harus eksplisit dengan "kwargs bintang ganda") adalah idiom umum Python karena menggunakan * dan ** notasi. Nama variabel khusus ini tidak diperlukan (misalnya, Anda dapat menggunakan *foos dan **bars), tetapi keberangkatan dari konvensi kemungkinan akan membuat marah rekan coders Python Anda.

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

Contoh 1

Fungsi berikut menjelaskan bagaimana mereka dapat digunakan, dan menunjukkan perilaku. Perhatikan nama b argumen 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 memberitahu kita

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

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

yang dicetak:

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

Kita juga dapat memanggilnya 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 yang membedakan. Fungsi-fungsi yang disebutkan berikut ini hanyalah pseudo-code untuk tujuan ilustratif.

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 tentu saja dapat mengekstraksi redundansi dengan dekorator, dan dengan demikian contoh di bawah kami menunjukkan bagaimana *args dan **kwargs bisa 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 jauh lebih ringkas, karena kami telah memfaktorkan 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 dengan memfaktorkan kode kami, yang *args dan **kwargs memungkinkan kami untuk melakukannya, kami mengurangi baris kode, meningkatkan keterbacaan dan pemeliharaan, dan memiliki lokasi kanonik tunggal untuk logika dalam program kami. Jika kita perlu mengubah bagian apa pun dari struktur ini, kita memiliki satu tempat untuk membuat setiap perubahan.


105
2017-10-14 16:34



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

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 posisional. Anda dapat menyebutnya dengan argumen kata kunci / bernama juga:

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 posisi 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 sekarang kita tahu definisi fungsi dengan posisi serta argumen kata kunci.

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

Harap perhatikan operator ini dapat digunakan di 2 area:

Sebuah) panggilan fungsi

b) definisi fungsi

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

Mari kita langsung ke contoh dan kemudian 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 a panggilan fungsi -

Operator '*' membongkar struktur data seperti daftar atau tupel ke dalam argumen yang dibutuhkan oleh definisi fungsi.

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

Sekarang mari kita pelajari penggunaan operator '*' di 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 fungsi definisi operator '*' mengemas argumen yang diterima ke dalam tuple.

Sekarang mari kita lihat contoh '**' 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 fungsi definisi Operator '**' mengemas argumen yang diterima ke dalam kamus.

Jadi ingat:

Di sebuah panggilan fungsi '*' membongkar struktur data tupel atau daftar ke argumen posisi atau kata kunci untuk diterima oleh definisi fungsi.

Di sebuah panggilan fungsi '**' membongkar struktur data kamus ke dalam argumen posisi atau kata kunci untuk diterima oleh definisi fungsi.

Di sebuah definisi fungsi '*' bungkus argumen posisi menjadi tuple.

Di sebuah definisi fungsi '**' bungkus argumen kata kunci ke dalam kamus.


37
2018-01-20 11:40



* dan ** memiliki penggunaan khusus dalam daftar argumen fungsi. * menyiratkan bahwa argumen itu adalah daftar dan ** menyiratkan bahwa argumen itu adalah kamus. Ini memungkinkan fungsi untuk mengambil nomor acak argumen


20
2017-09-11 04:33



Dari dokumentasi Python:

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

Jika argumen kata kunci tidak sesuai dengan nama parameter formal, pengecualian TypeError dinaikkan, kecuali parameter formal menggunakan sintaks "** identifier" ada; 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 yang berlebihan.


11
2017-08-31 15:07



Saya ingin memberikan contoh yang belum disebutkan orang lain

* Bisa juga membongkar a 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 argumen yang tidak dapat diperbaiki, dan mengembalikan generator.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

7
2017-11-08 16:50



Di Python 3.5, Anda juga dapat menggunakan sintaks ini di list, dict, tuple, dan set display (juga kadang disebut literal). Lihat PEP 488: Generalisasi Unpacking 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 fungsi panggilan.

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

(Terima kasih untuk mgilson untuk tautan PEP.)


6
2017-12-08 21:38



Sedangkan untuk operator bintang / splat telah digunakan diperluas di Python 3, saya suka tabel berikut yang berhubungan dengan penggunaan operator ini dengan fungsi. Operator splat dapat digunakan di dalam fungsi konstruksi dan dalam fungsi panggilan:

            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 meringkas Lorin Hochstein menjawab tapi saya merasa bermanfaat.


6
2017-11-30 18:28