اذهب إلى المحتوى
  • 0

خطأ بسبب المعامل += في بايثون

Adam Ebrahim

السؤال

أحاول التطبيق على OOP ولكن عند إستخدام المعامل += يحدث أمر غير متوقع، في الكود التالي يوجد صنفين foo و foo2 وعند عمل كائن من كل صنف وإضافة قيمة إلى القائمة bar يتم إضافتها أيضًا إلى الكائن الآخر!!

>>> class foo:
...     bar = []
...     def __init__(self,x):
...             self.bar += [x]
...
>>> class foo2:
...     bar = []
...     def __init__(self,x):
...             self.bar = self.bar + [x]
...
>>> f = foo(1)
>>> g = foo(2)
>>> f.bar
[1, 2]
>>> g.bar
[1, 2]
>>> f.bar += [3]
>>> f.bar
[1, 2, 3]
>>> g.bar
[1, 2, 3]

لماذا أصبح الكائن g يحتوي على نفس القائمة أيضًا؟

هذه المشكلة لا تحدث إن قمت بإستخدام الطريقة العادية كالتالي:

>>> f.bar = f.bar + [4]
>>> f.bar
[1, 2, 3, 4]
>>> g.bar
[1, 2, 3]
>>>

ما الفرق بين الطريقة الأولى والثانية؟

رابط هذا التعليق
شارك على الشبكات الإجتماعية

Recommended Posts

  • 1

السبب في اختلاف الدالة التي يتم استدعائها، حيث أن =+ في مثالك:

>>> f.bar += [3]

تقوم باستدعاء __iadd__ التي تعدل f.bar الأصلية.

أما:

>>> f.bar = f.bar + [4]

تقوم بإنشاء قائمة جديدة ثم إسنادها للمتغير حيث أنها تستدعي الدالة __add__

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

هناك نوعين من الخواص في بايثون هما : class attributes and instance attributes, حيث class attributes تتشارك نفس القيمة مع كل ال object يتم انشاءه من الصنف, أما ال instance attributes فهي فقط تنتمي للobject , انت هناك قمت بتعريف المتغير bar على أنه class attributes ولذلك سوف تتشارك جميع الكائنات قيمته, الحل أن نقوم بتعريف المتغير بداخل الكونستركتور كالتالي

class foo:
     def __init__(self,x):
        self.bar = []
        self.bar += [x]

الآن لو حاولت انشاء أكثر من كائن من نفس الصنف لن تتشارك الكائنات نفس القيمة

رابط هذا التعليق
شارك على الشبكات الإجتماعية

  • 0

كما أشار @محمد أبو عواد و @Wael Aljamal.
أولاً أنت تعرف القائمة bar على أنها  class attributes أي وكأنها static أي تتشارك القيمة مع كل الكائنات المأخوذة من الصف.
ثانياً في حالة استخادم += فهذا يقابل استدعاء الدالة  __iadd__ التي تقوم بتعديل القيمة الأصلية لل bar. أي أنها تغير قيمة الكائن الذي تعمل عليه.
أما  + فهذا يقابل استدعاء الدالة __add__ التي تقوم بإنشاء كائن جديد، أي في حالتنا سوف تنشئ نسخة من bar أي أن التعديل لن يتأثر به المتغير bar الأصلي.
ويمكنك التأكد بذلك عن طريق تجربة التالي:

>>> f.bar = f.bar + [4]
>>> print(f.bar) # [1, 2, 3, 4]
>>> print(g.bar)  # [1, 2, 3]
>>> foo.bar # [1, 2, 3]

مع ملاحظة أن التابع الخاص __iadd__ يحاول في البداية أن يعدل القيمة الأصلية للمتغير، وإذا لم ينجح (مثلاً قد يكون متحولاً ثابتاً أي لايمكن تعديل قيمته) فإنه يقوم بإنشاء نسخة جديدة منه، أي يسلك سلوك __add__.

رابط هذا التعليق
شارك على الشبكات الإجتماعية

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...