python - * arg و** kwargs؟




(8)

* arg و ** kwargs هي ميزات خاصة سحرية من بايثون. فكر في وظيفة يمكن أن تحتوي على عدد غير معروف من الحجج. على سبيل المثال ، لأي سبب من الأسباب ، تريد أن يكون لديك وظيفة تقوم بجمع عدد غير معروف من الأرقام (ولا ترغب في استخدام الدالة sum المضمنة). لذلك تكتب هذه الوظيفة:

def sumFunction(*args):
  result = 0
  for x in args:
    result += x
  return result

واستخدامها مثل: sumFunction (3،4،6،3،6،8،9).

** kwargs لديه وظيفة مختلفة. مع ** kwargs يمكنك إعطاء حجج الكلمة الرئيسية التعسفية إلى وظيفة ويمكنك الوصول إليها كإصدار.

def someFunction(**kwargs):
  if 'text' in kwargs:
    print kwargs['text']

استدعاء بعض الدالة (text = "foo") سوف يطبع foo.

لذلك أجد صعوبة في مفهوم *args **kwargs و **kwargs .

لقد تعلمت حتى الآن ما يلي:

  • *args = list of arguments - as argal arguments
  • **kwargs = القاموس - مفاتيحه تصبح وسيطات منفصلة للكلمات الرئيسية وتصبح القيم قيم هذه الحجج.

لا أفهم ما هي مهمة البرمجة التي سيكون هذا مفيدًا لها.

يمكن:

أعتقد أن إدخال القوائم والقواميس كحجج لدالة وفي نفس الوقت كحرف بدل ، حتى أتمكن من تمرير أي حجة؟

هل هناك مثال بسيط لتوضيح كيف يتم استخدام *args **kwargs و **kwargs ؟

كما استخدم البرنامج التعليمي الذي وجدته فقط "*" واسم متغير.

هل *args و **kwargs فقط placeholders أو هل تستخدم بالضبط *args **kwargs و **kwargs في التعليمات البرمجية؟


إليك مثال يستخدم 3 أنواع مختلفة من المعلمات.

def func(required_arg, *args, **kwargs):
    # required_arg is a positional-only parameter.
    print required_arg

    # args is a tuple of positional arguments,
    # because the parameter name has * prepended.
    if args: # If args is not empty.
        print args

    # kwargs is a dictionary of keyword arguments,
    # because the parameter name has ** prepended.
    if kwargs: # If kwargs is not empty.
        print kwargs

>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)

>>> func("required argument")
required argument

>>> func("required argument", 1, 2, '3')
required argument
(1, 2, '3')

>>> func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
required argument
(1, 2, '3')
{'keyword2': 'foo', 'keyword1': 4}

تُستخدم هذه المعلمات عادةً لوظائف البروكسي ، بحيث يمكن للوكيل تمرير أي معلمة إدخال إلى الدالة الهدف.

def foo(bar=2, baz=5):
    print bar, baz

def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
    print x
    foo(*args, **kwargs) # applies the "non-x" parameter to foo

proxy(23, 5, baz='foo') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar='asdas') # calls foo with bar='asdas' and leave baz default argument

ولكن بما أن هذه المعلمات تخفي أسماء المعلمات الفعلية ، فمن الأفضل تجنبها.


حالة واحدة حيث * args و ** kwargs مفيدة عند كتابة وظائف المجمع (مثل الديكور) التي تحتاج إلى أن تكون قادرة على قبول الحجج التعسفية لتمريرها إلى الوظيفة التي تم لفها. على سبيل المثال ، مصمم بسيط يقوم بطباعة الوسيطات وقيمة الإرجاع للدالة التي تم لفها:

def mydecorator( f ):
   @functools.wraps( f )
   def wrapper( *args, **kwargs ):
      print "Calling f", args, kwargs
      v = f( *args, **kwargs )
      print "f returned", v
      return v
   return wrapper

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

هذا يبدو معقولاً:

def myprint(*args):
    print *args

للأسف لم يتم تجميع (خطأ في بناء الجملة).

هذا يجمع:

def myprint(*args):
    print args

لكن يطبع الحجج على أنها صف ، وهذا ليس ما نريده.

هذا هو الحل الذي استقرت عليه:

def myprint(*args):
    for arg in args:
        print arg,
    print

مكان واحد حيث استخدام *args **kwargs و **kwargs مفيد جدا هو subclassing.

class Foo(object):
    def __init__(self, value1, value2):
        # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
        # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)

وبهذه الطريقة يمكنك تمديد سلوك فئة Foo ، دون الحاجة إلى معرفة الكثير عن Foo. يمكن أن يكون هذا مناسبًا تمامًا إذا كنت تقوم بالبرمجة إلى واجهة برمجة التطبيقات (API) التي قد تتغير. MyFoo مجرد تمرير جميع الحجج لفئة Foo.


يمكنك إلقاء نظرة على مستندات python (docs.python.org في الأسئلة الشائعة) ، ولكن بشكل أكثر تحديدًا للحصول على تفسير جيد للسيدة الغامضة التي تجادل و mwar kwargs (بإذن من archive.org) (الرابط الأصلي موجود هنا ).

باختصار ، يتم استخدام كلاهما عند استخدام معلمات اختيارية لوظيفة أو طريقة. كما يقول ديف ، * يستخدم arg عندما لا تعرف عدد الحجج التي يمكن تمريرها ، و ** kwargs عندما تريد التعامل مع المعلمات المحددة حسب الاسم والقيمة كما في:

myfunction(myarg=1)

بناء الجملة هو * و ** . الأسماء *args و **kwargs لا يتم إلا من خلال الاتفاقية ولكن لا توجد متطلبات صعبة لاستخدامها.

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

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

وبالمثل ، يتيح لك **kwargs التعامل مع الحجج المسماة التي لم تحددها مسبقا:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

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

def table_things(titlestring, **kwargs)

يمكنك أيضا استخدام كلاهما في نفس تعريف الدالة ولكن يجب أن تحدث *args قبل **kwargs .

يمكنك أيضًا استخدام الصيغة * و ** عند استدعاء وظيفة. فمثلا:

>>> def print_three_things(a, b, c):
...     print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat

كما ترون في هذه الحالة فإنه يأخذ قائمة (أو tuple) من العناصر ويفتحها. من خلال هذا يطابقها مع الحجج في الوظيفة. بالطبع ، قد يكون لديك * كلاهما في تعريف الدالة وفي استدعاء الدالة.







kwargs