الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

لم افهم *args and **kwargs

بدأه phpcraft في 16 مايو 2013 · 11 رد · 1,337 مشاهدة · في لغة Python
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله

ارى في كثير من التطبيقات والدروس وخصوصا مع الدوال العبارة التالية :

 

*args and **kwarg

فماذا تعني ارجو  التوضيح مع مثال لاني بحثت كثيرا لكن لم استوعبها

#2

حسنا ، لنشرحها بالتدريج

 

args

 

بداية

 

 
 
>>> def sum_elements(listofelements):
...     print "listofelements=", str(listofelements)
...     sum = 0
...     for el in listofelements:
...             sum += el
...     return sum
... 
>>> sum_elements([1,2,3,4,5])
listofelements= [1, 2, 3, 4, 5]
15

 

الكود يعمل بصورة رائعة ، ولكن ظهرت لنا مشكلة وهي 

أنني لاأريد أن أستدعي الدالة sum_elements بهذا الشكل

 

 

 sum_elements([1,2,3,4,5])

ولكن بهذا الشكل

 

 

 
>>> sum_elements(1,2,3,4,5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sum_elements() takes exactly 1 argument (5 given)

 

فالخطأ الناتج أن هذه الدالة تأخذ معامل واحد وليس 5 معاملات!

فربما تريد أن تعيد تعريفها كالتالي

 

def sum_elements(a,b,c,d,e):return a+b+c+d+e

 

الآن كيف أخبر sum_elements أن تجمع كل المعاملات -ربما لاأريد أن أمرر 5 معاملات ربما فقط 4  أو ربما 2 او ربما 10- التي ستمرر لها ؟

 

الحل: فلنذهب إلى *args وهي تعبر عن المعاملات الممررة أيا كانت بإسم args

 

 
>>> def sum_elements2(*args):
...     print "ARGS= ", args
...     sum = 0
...     for el in args:
...             sum += el
...     return sum
...

 

 

 
 
>>> sum_elements2(1,2)
ARGS=  (1, 2)
3
>>> sum_elements2(1,2,3,4)
ARGS=  (1, 2, 3, 4)
10
>>> sum_elements2(1,2,3,4, 5, 6, 7, 8)
ARGS=  (1, 2, 3, 4, 5, 6, 7, 8)
36

 

طيب نقطة أخيرة ، إذا أردت أن أجمع عدد الأرقام من 0, 10 ولاأريد أن أكتب 10 معاملات ولدي الدالة range جاهزة تمدني ب list بها هذه الارقام

 

 

 
 
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sum_elements2(range(10))
ARGS=  ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9],)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in sum_elements2
TypeError: unsupported operand type(s) for +=: 'int' and 'list'

سيظهر لي هذا الخطأ ، وذلك لأننا مررنا list بدل من عدد من العناصر ال integers

 

sum_elements2([0,1,2,3,4,5,6,7,8,9])

 

كيف نحل هذه المشكلة ؟ يجب أن توجد طريقة لنحول هذه ال list إلى مجموعة حرة من العناصر 

 

بكل بساطة إستخدم المعامل * في بايثون لما يسمى ب unpack arguments (يسمى splat في بعض اللغات)

 

 

 
>>> sum_elements2(*range(10))
ARGS=  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
45

 

 

ماذا عن **kwargs 

 

حسنا، هي تسمى unpacking dictionary كما سمينا ال *args بإسم unpacking argument

 

 

 
 
def ls_options(showdirs=True, showsize=True, showperms=True, showversion=False, showlatime=False sort=False, showall=False):
    if showdirs:
        # dosomething
        pass
    
    if sort:
        # dosomething to sort
        pass
    
    if showsize=:
        # something to 
        pass

هل يعقل أن تكتب العشرات من المعاملات الإفتراضية في تعريف الدالة ؟

فالحل هو إستخدام شئ عام أنك ستشير لمعاملات إفتراضية عديدة عبر **kwargs

 

 

 
                
 
def ls_options2(**kwargs): 
    print "KWARGS: ", kwargs
    
    if kwargs.has_key('showdirs'):
        # dosomething
        pass
    
    if kwargs.has_key('sort'):
        # dosomething to sort
        pass
    
    if kwargs.has_key('showsize'):
        # something to 
        pass
        
 ls_options2(showsize=True, showtime=True, showall=True, sort=False)
 
KWARGS:  {'showsize': True, 'showtime': True, 'sort': False, 'showall': True}

تم تعديل هذه المشاركة بواسطة ahmed_youssef في 16 مايو 2013 في 12:11

1
(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#3

سلمت يداك شرح جميل والله ومفهوم

#4

استاذنا الغالي شرح في غاية الروعة
اشكرك جزيل الشكر

الان فهمت

#5

اسف لكني اعود لكم مره اخرى 

    

مثلا هذا الكود للجانغو تلخبط علي انا كثيرا

 

class Comment(BaseModel):
    author  = CharField(max_length=60, blank=True)
    body    = TextField()
    post    = ForeignKey(Post, related_name="comments",  blank=True, null=True)
    created = DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u"%s: %s" % (self.post, self.body[:60])

    def save(self, *args, **kwargs):
        """Email when a comment is added."""
        if notify:
            tpl            = "Comment was was added to '%s' by '%s': \n\n%s"
            message        = tpl % (self.post, self.author, self.body)
            from_addr      = "no-reply@mydomain.com"
            recipient_list = ["myemail@mydomain.com"]

            send_mail("New comment added", message, from_addr, recipient_list)
        super(Comment, self).save(*args, **kwargs)

 

لم افهم كيف تم استعمالها الان هذا موديول للتعليقات 

بحيث عمليا تغييرت امور كثيره

وبالمناسبة ماهي الدالة super

وشكرا

تم تعديل هذه المشاركة بواسطة phpcraft في 17 مايو 2013 في 07:03

#6
class Comment(BaseModel):
    ....

    def save(self, *args, **kwargs):
        """Email when a comment is added."""
        #do some extra stuff
        ....
        #then call the parent.save method
        
        super(Comment, self).save(*args, **kwargs)

 

 

هذا الصف يرث من BaseModel 

ويريد التعديل فيما يحدث عندما تضغط Comment.save() فيريد ربما الإعلام بالبريد! -لايريد ال default behavior أو السلوك الإفتراضي عند تنفيذ دالة save- 

فقام بإعادة تعريفها ليفعل فيها الأشياء الإضافية كإرسال إيميل للمستخدم بوجود تعليق جديد "ثم" إستدعى السلوك الإفتراضى من الأب BaseModel 

 

super دالة تقوم بإعادة الأب ...

 

بالتوفيق

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#7

جزاك الله خيرا
ويجب علي ان اعود لدراسة الكلاسات

#8
يجب عليك تعلم هذا النوع من البرمجة 

والا فلن تذهب بعيدا
#9

شكرا على النصيحة سابدا من الان بحثا عن كتاب او دروس للبدء من البداية وحتى النهاية ان شاء الله

#10
يمكنك مراجعة الموقع الخاص بي

لا اقصد الاشهار  :D
#12

نعم

مواضيع مشابهة