سؤال

أنا بانتظام ترغب في التحقق إذا كان كائن يحتوي على الأعضاء أو لا.مثال على ذلك هو إنشاء المفرد في وظيفة.لهذا الغرض يمكنك استخدام hasattr مثل هذا:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance

ولكن يمكنك أيضا القيام بذلك:

class Foo(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Foo()
            return self.instance

هو أسلوب واحد أفضل من الآخر ؟

تحرير: وأضاف @classmethod ...ولكن لاحظ أن السؤال هو لا حول كيفية جعل المفرد ولكن كيفية التحقق من وجود عضو في كائن.

تحرير: هذا مثال نموذجي من شأنه أن يكون استخدام:

s = Foo.singleton()

ثم s هو كائن من نوع Foo, نفس كل مرة.و عادة ما تسمى الأسلوب عدة مرات.

هل كانت مفيدة؟

المحلول

هذه هي اثنين من منهجيات مختلفة:No 1 LBYL (انظر قبل أن تقفز) no 2 EAFP (أسهل طلب المغفرة من إذن).

Pythonistas عادة تشير إلى أن EAFP هو أفضل ، مع الحجج في اسلوب "ما إذا كانت العملية بإنشاء الملف بين الوقت يمكنك اختبار ذلك الوقت حاول إنشاء ذلك بنفسك؟".هذه الحجة لا تنطبق هنا لكن الفكرة العامة.الاستثناءات لا ينبغي أن تعامل على أنها أيضا استثنائية.

الحكمة في حالتك —منذ إنشاء استثناء مديري (إن try الكلمة) هو رخيص جدا في CPython أثناء إنشاء استثناء (على raise الكلمات الرئيسية والداخلية استثناء الخلق) ما هي مكلفة نسبيا— باستخدام no2 باستثناء رفع مرة واحدة فقط ؛ بعد ذلك, يمكنك فقط استخدام العقار.

نصائح أخرى

أنا فقط حاولت لقياس مرات:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance



class Bar(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Bar()
            return self.instance



from time import time

n = 1000000
foo = [Foo() for i in xrange(0,n)]
bar = [Bar() for i in xrange(0,n)]

print "Objs created."
print


for times in xrange(1,4):
    t = time()
    for d in foo: d.singleton()
    print "#%d Foo pass in %f" % (times, time()-t)

    t = time()
    for d in bar: d.singleton()
    print "#%d Bar pass in %f" % (times, time()-t)

    print

على الجهاز الخاص بي:

Objs created.

#1 Foo pass in 1.719000
#1 Bar pass in 1.140000

#2 Foo pass in 1.750000
#2 Bar pass in 1.187000

#3 Foo pass in 1.797000
#3 Bar pass in 1.203000

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

ذلك يعتمد على أي حالة "نموذجية" ، لأن الاستثناءات نموذج, جيد, ظروف شاذة.لذلك ، إذا كانت حالة نموذجية هي أن instance السمة التي يجب أن تكون موجودة ، ثم استخدام رمز الثاني الاسلوب.إذا لا وجود instance كما النموذجية لها instance, ثم استخدام النمط الأول.

في حالة إنشاء المفرد ، أنا أميل إلى الذهاب مع النمط الأول, لأن خلق المفرد الوقت الأولي هو نموذجي حالة استخدام.:-)

خارج الموضوع قليلا في طريقة استخدامه.ووحدانية مبالغ فيه ، و "مشترك-الدولة" طريقة فعالة ، في الغالب ، نظيفة جدا في بيثون ، على سبيل المثال:

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state
    # and whatever else you want in your class -- that's all!

الآن في كل مرة كنت تفعل:

obj = Borg()

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

يجب أن نتفق مع كريس.تذكر, لا تحسين حتى كنت في الواقع تحتاج إلى القيام بذلك.أنا حقا أشك في التحقق من وجود سيكون عنق الزجاجة في أي برنامج.

رأيت http://code.activestate.com/recipes/52558/ باعتبارها وسيلة للقيام بذلك أيضا.Uncommented نسخة من هذا الرمز ("سبام" هو مجرد طريقة عشوائية فئة واجهة):

class Singleton:
    class __impl:
        def spam(self):
            return id(self)
    __instance = None
    def __init__(self):
        if Singleton.__instance is None:
            Singleton.__instance = Singleton.__impl()
        self.__dict__['_Singleton__instance'] = Singleton.__instance
    def __getattr__(self, attr):
        return getattr(self.__instance, attr)
    def __setattr__(self, attr, value):
        return setattr(self.__instance, attr, value)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top