الفرق بين تحديد عضو في __init__ إلى تعريفه في الجسم الطبقي في بيثون؟

StackOverflow https://stackoverflow.com/questions/1549722

  •  20-09-2019
  •  | 
  •  

سؤال

ما هو الفرق بين العمل

class a:
   def __init__(self):
       self.val=1

للقيام ب

class a:
   val=1
   def __init__(self):
       pass
هل كانت مفيدة؟

المحلول

class a:
   def __init__(self):
       self.val=1

هذا يخلق فصلًا (في PY2 ، وهو مطحون ، إرث ، على الطراز القديم ، لا تفعل ذلك! صف دراسي؛ في PY3 ، اختفت الطبقات القديمة القديمة السيئة في النهاية ، لذلك سيكون هذا فئة من النوع الوحيد - النوع الجيد*الذي يتطلب class a(object): في PY2) بحيث يبدأ كل مثيل مع مرجعه الخاص إلى كائن INTEGER 1.

class a:
   val=1
   def __init__(self):
       pass

هذا ينشئ فئة (من نفس النوع) والتي لها إشارة إلى كائن عدد صحيح 1 (تبدأ مثيلاتها مع عدم وجود مرجع للترتيب).

للمنفصات مثل int القيم ، من الصعب رؤية فرق عملي. على سبيل المثال ، في كلتا الحالتين ، إذا فعلت لاحقًا self.val = 2 في حالة واحدة من a, ، هذا سوف يجعل نموذج المرجع (الإجابة الحالية خاطئة للغاية في هذا الصدد).

التمييز مهم ل متقلب الكائنات ، لأن لديهم أساليب متحولة ، لذلك من الأهمية بمكان معرفة ما إذا كانت قائمة معينة فريدة من نوعها أو مشتركة بين جميع الحالات. لكن ل ثابت الكائنات ، نظرًا لأنه لا يمكنك تغيير الكائن بنفسه ولكن فقط التعيين (على سبيل المثال self.val, ، والتي ستجعل دائمًا مرجعًا للرباط) ، إنها بسيطة جدًا.

فقط حول الفرق الوحيد ذي الصلة لـ Immutables: إذا قمت بتعيين لاحقًا a.val = 3, ، في الحالة الأولى ، سيؤثر هذا على ما يُنظر إليه self.val حسب كل حالة (باستثناء الحالات التي لها self.val تعيين إلى ، أو إجراءات مكافئة) ؛ في الحالة الثانية ، لن يؤثر ذلك على ما يُنظر إليه self.val بأي حال من الأحوال (باستثناء الحالات التي قمت بها del self.val أو إجراءات مكافئة).

نصائح أخرى

وقد أوضح آخرون الاختلافات التقنية. سأحاول شرح سبب رغبتك في استخدام متغيرات الفصل.

إذا كنت تقوم بتسهيل الفصل مرة واحدة فقط ، فإن متغيرات الفصل بشكل فعال نكون متغيرات سريعة. ومع ذلك ، إذا كنت تقوم بعمل العديد من النسخ ، أو ترغب في مشاركة الحالة بين بعض الحالات ، فإن متغيرات الفصل مفيدة للغاية. علي سبيل المثال:

class Foo(object):
    def __init__(self):
        self.bar = expensivefunction()

myobjs = [Foo() for _ in range(1000000)]

سوف يتسبب في استدعاء باهظة الثمن () مليون مرة. إذا كانت ستعيد نفس القيمة في كل مرة ، على سبيل المثال ، جلب معلمة تكوين من قاعدة بيانات ، فيجب عليك التفكير في نقلها إلى تعريف الفئة بحيث يتم استدعاؤها مرة واحدة فقط ثم مشاركتها عبر جميع الحالات.

أنا أيضا استخدام متغيرات الفئة كثيرا عند نتائج التذاكر. مثال:

class Foo(object):
    bazcache = {}

    @classmethod
    def baz(cls, key):
        try:
            result = cls.bazcache[key]
        except KeyError:
            result = expensivefunction(key)
            cls.bazcache[key] = result
        return result

في هذه الحالة ، BAZ هي طريقة الفصل ؛ لا تعتمد نتائجها على أي متغيرات مثيل. هذا يعني أنه يمكننا الاحتفاظ بنسخة واحدة من ذاكرة التخزين المؤقت للنتائج في متغير الفصل ، بحيث لا تخزن نفس النتائج عدة مرات ، و 2) يمكن أن يستفيد كل مثيل من النتائج التي تم تخزينها مؤقتًا من مثيلات أخرى.

لتوضيح ، افترض أن لديك مليون حالة ، كل منها يعمل على نتائج بحث Google. من المحتمل أن تفضل كثيرًا أن تشترك كل هذه الكائنات في هذه النتائج بدلاً من تنفيذ كل واحدة من البحث وانتظار الإجابة.

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

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

أولا فئة تحديد اثنين من سمات مثيل.

>>> class A(object):
...     def __init__(self):
...         self.number = 45
...         self.letters = ['a', 'b', 'c']
... 

ثم فصل يحدد اثنين من الصفات الصف.

>>> class B(object):
...     number = 45
...     letters = ['a', 'b', 'c']
... 

الآن نستخدمها:

>>> a1 = A()
>>> a2 = A()
>>> a2.number = 15
>>> a2.letters.append('z')

وكل شيء على ما يرام:

>>> a1.number
45
>>> a1.letters
['a', 'b', 'c']

استخدم الآن تباين سمة الفصل:

>>> b1 = B()
>>> b2 = B()
>>> b2.number = 15
>>> b2.letters.append('z')

وكل شيء ... حسنا ...

>>> b1.number
45
>>> b1.letters
['a', 'b', 'c', 'z']

نعم ، لاحظ أنه عند تغيير ، سمة الفئة القابلة للتغيير التي تغيرت لجميع الفئات. هذا عادة ليس ما تريد.

إذا كنت تستخدم ZODB ، فأنت تستخدم الكثير من سمات الفصل لأنها طريقة مفيدة لترقية الكائنات الموجودة بسمات جديدة ، أو إضافة معلومات على مستوى الفصل لا تستمر. وإلا يمكنك تجاهلهم إلى حد كبير.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top