Checking for member existence in Python

前端 未结 5 1404
北恋
北恋 2020-12-01 14:23

I regularly want to check if an object has a member or not. An example is the creation of a singleton in a function. For that purpose, you can use hasattr like

相关标签:
5条回答
  • 2020-12-01 14:34

    These are two different methodologies: №1 is LBYL (look before you leap) and №2 is EAFP (easier to ask forgiveness than permission).

    Pythonistas typically suggest that EAFP is better, with arguments in style of "what if a process creates the file between the time you test for it and the time you try to create it yourself?". This argument does not apply here, but it's the general idea. Exceptions should not be treated as too exceptional.

    Performance-wise in your case —since setting up exception managers (the try keyword) is very cheap in CPython while creating an exception (the raise keyword and internal exception creation) is what is relatively expensive— using method №2 the exception would be raised only once; afterwards, you just use the property.

    0 讨论(0)
  • 2020-12-01 14:34

    I have to agree with Chris. Remember, don't optimize until you actually need to do so. I really doubt checking for existence is going to be a bottleneck in any reasonable program.

    I did see http://code.activestate.com/recipes/52558/ as a way to do this, too. Uncommented copy of that code ("spam" is just a random method the class interface has):

    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)
    
    0 讨论(0)
  • 2020-12-01 14:49

    It depends on which case is "typical", because exceptions should model, well, atypical conditions. So, if the typical case is that the instance attribute should exist, then use the second code style. If not having instance is as typical as having instance, then use the first style.

    In the specific case of creating a singleton, I'm inclined to go with the first style, because creating a singleton the initial time is a typical use case. :-)

    0 讨论(0)
  • 2020-12-01 14:50

    I just tried to measure times:

    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
    

    On my machine:

    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
    

    It seems that try/except is faster. It seems also more readable to me, anyway depends on the case, this test was very simple maybe you'd need a more complex one.

    0 讨论(0)
  • 2020-12-01 14:51

    A little off-topic in the way of using it. Singletons are overrated, and a "shared-state" method is as effective, and mostly, very clean in python, for example:

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

    Now every time you do:

    obj = Borg()
    

    it will have the same information, or, be somewhat the same instance.

    0 讨论(0)
提交回复
热议问题