python - ماذا يفعل **(النجمة المزدوجة / النجمة)و *(النجم / النجمة)بالنسبة للمعلمات؟




syntax parameter-passing identifier kwargs (13)

من وثائق بايثون:

إذا كان هناك المزيد من الوسيطات الموضعية أكثر من وجود فتحات المعلمات الرسمية ، فستظهر استثناء TypeError ، ما لم تكن هناك معلمة رسمية تستخدم بناء الجملة "* identifier" ؛ في هذه الحالة ، تتلقى المعلمة الرسمية مجموعة تحتوي على الوسائط الموضعية الزائدة (أو مجموعة فارغة إذا لم تكن هناك وسيطات زائدة في الموضع).

إذا لم تتطابق أي وسيطة كلمة رئيسية مع اسم معلمة رسمي ، فسيتم طرح استثناء TypeError ، ما لم تكن هناك معلمة رسمية تستخدم بناء الجملة "** identifier" ؛ في هذه الحالة ، ستتلقى هذه المعلمة الرسمية قاموسًا يحتوي على وسيطات كلمات رئيسية زائدة (باستخدام الكلمات الرئيسية كمفاتيح وقيم وسيطة كقيم مقابلة) ، أو قاموس فارغ (جديد) إذا لم تكن هناك وسيطات كلمات رئيسية زائدة.

في تعريفات الطريقة التالية ، ما الذي يفعله * و ** لـ param2 ؟

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

في حين تم expanded الاستخدامات لمشغلي النجمة / الملحوظة في Python 3 ، فأنا أحب الجدول التالي لأنه يتعلق باستخدام هذه المشغلات مع الوظائف . يمكن استخدام مشغّل splat (مشغلات splat) داخل بناء الوظائف وفي استدعاء الدالة:

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

هذا حقا يخدم فقط لتلخيص answer لورين Hochstein ولكن أجد أنه من المفيد.


تعني كلمة "مفرد" أنه يمكن أن يكون هناك أي عدد من الحجج الموضعية الإضافية. يمكن استدعاء foo(1,2,3,4,5) مثل foo(1,2,3,4,5) . في جسم foo () param2 هو تسلسل يحتوي على 2-5.

المزدوجة ** تعني أنه يمكن أن يكون هناك أي عدد من المعلمات المسماة إضافية. يمكن استدعاء bar() مثل bar(1, a=2, b=3) . في الجزء الأساسي من bar () param2 ، هناك قاموس يحتوي على {'a': 2، 'b': 3}

مع التعليمة البرمجية التالية:

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)

الانتاج هو

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

أريد أن أعطي مثالاً لم يذكره الآخرون

* يمكن أيضا فك المولد

مثال من وثيقة Python3

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

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

unzip_x سيكون [1 ، 2 ، 3] ، unzip_y سيكون [4 ، 5 ، 6]

يتلقى zip () عدة erytable args ، ويعيد مولدًا.

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

بالإضافة إلى مكالمات الوظيفة ، * args و ** kwargs مفيدة في التسلسل الهرمي للفئات وأيضا تجنب الاضطرار إلى كتابة __init__ method في Python. يمكن أن يشاهد استخدام مماثل في أطر العمل مثل رمز Django.

فمثلا،

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

يمكن أن تكون فئة فرعية

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

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

ثم يتم إنشاء فئة فرعية باسم

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

أيضاً ، يمكن فئة فرعية ذات سمة جديدة التي معنى فقط إلى ذلك مثيل فئة فرعية استدعاء الفئة الأساسية __init__ تحميل إعداد السمات. يتم ذلك من خلال * arg و ** kwargs. kwargs تستخدم أساسا بحيث يمكن قراءة التعليمات البرمجية باستخدام الوسائط المسماة. فمثلا،

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)

والتي يمكن أن تثبت على أنها

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

الرمز الكامل موجود here


ماذا يفعل ** (نجمة مزدوجة) و * (نجمة) للمعلمات

فهي تسمح بتعريف الدوال لقبولها وللمستخدمين تمرير أي عدد من الحجج ، الموضعية ( * ) والكلمة الرئيسية ( ** ).

تحديد وظائف

*args يسمح لأي عدد من الوسيطات الموضعية الاختيارية (المعلمات) ، والتي سيتم تعيينها إلى tuple يُسمى args .

**kwargs يسمح لأي عدد من الحجج الكلمات الرئيسية الاختيارية (المعلمات) ، والتي ستكون في dict يدعى kwargs .

يمكنك (ويجب) اختيار أي اسم مناسب ، ولكن إذا كانت النية هي أن تكون الحجج ذات دلالات غير محددة ، فإن kwargs و kwargs هي أسماء قياسية.

التوسع ، وتجاوز أي عدد من الحجج

يمكنك أيضًا استخدام *args **kwargs و **kwargs لتمرير المعلمات من القوائم (أو أي تكراري) و dicts (أو أي تخطيط) ، على التوالي.

لا تحتاج الدالة التي تستلم المعلمات إلى معرفة أنها يتم توسيعها.

على سبيل المثال ، لا يتوقع xrange Python 2 بشكل صريح *args ، ولكن بما أنه يأخذ 3 أعداد صحيحة كوسيطة:

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

كمثال آخر ، يمكننا استخدام توسيع dict في str.format :

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

جديد في Python 3: تعريف الدالات مع الوسيطات الأساسية فقط

يمكنك الحصول على وسيطات kwarg2 رئيسية فقط بعد *args - على سبيل المثال ، هنا ، يجب إعطاء kwarg2 كوسيطة للكلمة الرئيسية - وليس kwarg2 :

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

الاستعمال:

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

أيضًا ، * يمكن استخدامه بنفسه للإشارة إلى أن الكلمات الرئيسية فقط تتبع الوسيطات ، دون السماح بالحجج الموضعية غير المحدودة.

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

هنا ، يجب أن تكون kwarg2 مرة أخرى حجة الكلمة الرئيسية المسماة بشكل صريح:

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

ولم يعد بإمكاننا قبول حجج موقوتة غير محدودة لأننا لا نملك *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

مرة أخرى ، ببساطة أكثر ، هنا نحن بحاجة إلى إعطاء kwarg بالاسم ، وليس الموقع:

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

في هذا المثال ، نرى أنه إذا حاولنا تمرير الأمر بشكل kwarg ، kwarg على خطأ:

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

يجب أن نمرر بوضوح معلمة kwarg كوسيطة أساسية.

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

بيثون 2 متوافقة مع العروض

*args (عادةً ما يُقال "star-args") و **kwargs (يمكن أن يكون ضمناً النجوم بـ "kwargs" ، ولكن كن صريحًا بـ "kwargs star-star") هي العبارات الشائعة لـ Python لاستخدام * و * notation . هذه الأسماء المتغيرة المحددة غير مطلوبة (على سبيل المثال ، يمكنك استخدام *foos و **bars ) ، ولكن من المرجح أن يؤدي غضبك من الاتفاقية إلى إغضاب زملائك في بيثون.

نستخدمها عادة عندما لا نعرف ما الذي ستحصل عليه وظيفتنا أو عدد الحجج التي قد نمررها ، وأحيانًا حتى عند تسمية كل متغير على حدة ستصبح فوضويًا ومكررًا جدًا (ولكن هذه حالة يكون فيها عادةً صريحًا أفضل من الضمني).

مثال 1

تصف الوظيفة التالية كيف يمكن استخدامها ، ويوضح السلوك. لاحظ أنه سيتم استهلاك الوسيطة b بواسطة الوسيطة الموضعية الثانية من قبل:

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

يمكننا التحقق من المساعدة عبر الإنترنت لتوقيع الوظيفة ، help(foo) ، التي تخبرنا بذلك

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

دعنا نسمي هذه الوظيفة بـ foo(1, 2, 3, 4, e=5, f=6, g=7)

الذي يطبع:

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}

مثال 2

يمكننا أيضًا أن نسميها باستخدام وظيفة أخرى ، والتي نقدم لها فقط 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) مطبوعة:

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}

مثال 3: الاستخدام العملي في الديكور

حسنًا ، ربما لا نرى الأداة بعد. لذا تخيل أن لديك وظائف متعددة مع شفرة مكررة قبل و / أو بعد رمز التفريق. تعتبر الدالات المسماة التالية مجرد رمز زائف لأغراض توضيحية.

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

قد نكون قادرين على التعامل مع هذا الأمر بشكل مختلف ، ولكن يمكننا بالتأكيد استخلاص التكرار مع مصمم ، وهكذا يوضح المثال أدناه كيف يمكن أن يكون كل من *args **kwargs و **kwargs مفيدًا جدًا:

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

والآن يمكن كتابة كل دالة ملفوفة بشكل أكثر إيجازًا ، حيث قمنا بتخزين التكرار:

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

ومن خلال احتساب الشفرة الخاصة بنا ، والتي تسمح لنا *args **kwargs و **kwargs بالقيام بذلك ، فإننا نقوم بتخفيض أسطر الشفرة ، وتحسين قابلية القراءة والصيانة ، ولدينا مواقع قانونية أساسية للمنطق في برنامجنا. إذا كنا بحاجة إلى تغيير أي جزء من هذه البنية ، لدينا مكان واحد لإجراء كل تغيير.


في Python 3.5 ، يمكنك أيضًا استخدام بناء الجملة هذا في list ، dict ، tuple ، set شاشات العرض (وتسمى أحيانًا القيم الحرفية). انظر PEP 488: تعميم تفريغ إضافية .

>>> (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}

كما يسمح أيضًا بتفريغ العديد من المقتطفات في مكالمة واحدة.

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

(شكرا ل mgilson للارتباط PEP.)


دعونا نفهم أولاً ما هي الحجج الموضعية ووسائط الكلمات الرئيسية. فيما يلي مثال لتعريف الوظيفة مع الوسيطات Positional.

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

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

إذن هذا تعريف وظيفة مع الوسيطات الموضعية. يمكنك الاتصال به باستخدام الكلمات الرئيسية / الوسائط المسماة أيضًا:

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

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

الآن دعنا ندرس مثالا لتعريف الوظيفة مع وسيطات الكلمات الرئيسية :

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

يمكنك الاتصال بهذه الوظيفة مع الوسيطات الموضعية أيضًا:

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

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

لذلك نحن نعرف الآن تعريفات الدالة مع الموضعية بالإضافة إلى وسائط الكلمات الرئيسية.

الآن دعنا ندرس المشغل "*" و "**".

يرجى ملاحظة يمكن استخدام هذه المشغلين في منطقتين:

أ) استدعاء وظيفة

ب) تعريف الدالة

استخدام المشغل "*" و "**" في استدعاء الوظيفة.

دعونا نصل مباشرة إلى مثال ثم نناقشه.

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.

لذلك تذكر

عند استخدام عامل التشغيل "*" أو "**" في مكالمة دالة -

يقوم المشغل '*' بتفكيك بنية البيانات مثل القائمة أو المجموعة في الوسيطات التي يحتاج إليها تعريف الدالة.

يقوم المشغل '**' بتفكيك القاموس إلى وسائط يحتاج إليها تعريف الدالة.

الآن دعونا دراسة استخدام المشغل '*' في تعريف الوظيفة . مثال:

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

في تعريف الوظيفة يقوم عامل التشغيل '*' بحزم الوسيطات المستلمة في مجموعة.

الآن دعنا نرى مثالاً على "**" المستخدم في تعريف الوظيفة:

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

في تعريف الوظيفة يقوم عامل التشغيل "**" بتعبئة الوسيطات المستلمة في أحد القواميس.

لذلك تذكر:

في دالة استدعاء هيكل البيانات '*' unpacks من tuple أو قائمة في الوسيط الموضعي أو الكلمة الرئيسية ليتم استلامها بواسطة تعريف الدالة.

في إحدى الوظائف ، تقوم بنية بيانات "**" بفك ضغط القاموس إلى وسيطات موضعية أو كلمة رئيسية ليتم استلامها بواسطة تعريف الدالة.

في تعريف الدوال ، يحزم "*" الوسيطات الموضعية في المجموعة.

في تعريف الدالة ، تقوم "**" بتعبئة وسيطات الكلمات الرئيسية إلى قاموس.


مثال جيد على استخدام كل من في وظيفة هو:

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

تجدر الإشارة أيضًا إلى أنه يمكنك استخدام * و ** عند إجراء وظائف الاتصال أيضًا. هذا اختصار يسمح لك بتمرير وسيطات متعددة لوظيفة مباشرة باستخدام إما قائمة / مجموعة أو قاموس. على سبيل المثال ، إذا كان لديك الوظيفة التالية:

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

يمكنك القيام بأشياء مثل:

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

ملاحظة: يجب تسمية المفاتيح في mydict تماماً مثل معلمات الدالة foo . وإلا فإنه سيرمي 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'

إن *args و **kwargs هي لغة شائعة تسمح بالعدد العشوائي من الحجج للوظائف كما هو موصوف في القسم أكثر حول تحديد الوظائف في وثائق Python.

سيعطيك الـ *args كل معلمات الدالة على أنها tuple :

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

**kwargs كل الحجج الرئيسية باستثناء تلك المقابلة لمعلمة رسمية مثل القاموس.

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

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

يمكن مزج كل من التعابير مع الحجج العادية للسماح بمجموعة من الحجج الثابتة والمتغيرة.

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

استخدام آخر للمصطلح *l هو فك حزم قوائم الوسيطات عند استدعاء وظيفة.

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

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

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

في بايثون 3 ، من الممكن استخدام *l على الجانب الأيسر من الواجب ( Extended Iterable Unpacking ) ، على الرغم من أنه يعطي قائمة بدلاً من tuple في هذا السياق:

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

أيضا Python 3 يضيف دلالات جديدة (راجع PEP 3102 ):

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

تقبل هذه الوظيفة فقط 3 حجج موضعية ، وكل شيء بعد * يمكن تمريره فقط كوسائط كلمات رئيسية.


سيساعدك هذا المثال على تذكر *args **kwargs ، **kwargs وحتى super و **kwargs في Python دفعة واحدة.

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

للتكرار أكثر من المفاتيح ، يكون أبطأ ولكن من الأفضل استخدام my_dict.keys() . إذا حاولت فعل شيء كالتالي:

for key in my_dict:
    my_dict[key+"-1"] = my_dict[key]-1

فإنه ينشئ خطأ وقت التشغيل لأنك تقوم بتغيير المفاتيح أثناء تشغيل البرنامج. إذا كنت for key in my_dict تمامًا لخفض الوقت ، فاستخدم for key in my_dict طريقة for key in my_dict ، ولكن تم تحذيرك ؛).





python syntax parameter-passing identifier kwargs