开发者

String vs. Enum for checking type of object in Python

开发者 https://www.devze.com 2023-04-08 19:14 出处:网络
Say I have an object called Tag, and I have three types of tags as indicated by an instance variable in the following way,

Say I have an object called Tag, and I have three types of tags as indicated by an instance variable in the following way,

class Tag(object):
    def __init__(self, name, type):
        self.name = name
        self.type = type

t1 = Tag("blue", "cold")
t2 = Tag("red", "warm")
t3 = Tag("black", "hot")

Let's say I only allowed three types: cold, warm, and hot. Would it be better to go checking if it is one of these types like this?

if t1.type == "cold":
    # do something
elif t1.type == "warm":
    # do something else
else t1.type == "hot":
    # do something even elser

Or should I create an enum-like object like the one from this question,

class Type:
    COLD=1
    WARM=2        
    HOT=3

And instead create Tags like this?

t1 = Tag("blue", Type.COLD)

The reason I ask this question is because I heard a lot of processing power goes into comparing strings, and even though these are short 3, 4 letter long words, it is possible that I'd be making tens of thousands of compari开发者_JAVA技巧sons of these types. Do you think its worth it to go creating enum objects for determining the type of an object as in the example I've shown above? Or is there a better way to do what I'm attempting to do?


It's possible the performance difference may not be significant enough for you to worry about it. You should make a simple test if you're concerned about performance. Use Python's timeit module to test the performance of both cases.


I wouldn't be worried about the performance of this unless profiling shows that it indeed is a problem. If you're using an IDE, the enum approach has the benefit of typo-checking.


I would go with a combination approach -- have the 'enum' be part of the Tag class, accept a string for initialization, and then convert it. Also, instead of using a bunch of if/else branches, you can use a dict to create a dispatch table.

class Tag(object):
    COLD = 0
    WARM = 1
    HOT = 2
    def __init__(self, name, temp):
        if temp.upper() not in ('COLD', 'WARM', 'HOT'):
            raise ValueError("Invalid temp: %r" % temp)
        self.temp = getattr(self, temp.upper())
        self.name = name
    def process(self):
        func = self.temp_dispatch[self.temp]
        func(self)  # NOTE:  have to pass 'self' explicitly
    def cold(self):
        print('brrr')
    def warm(self):
        print('ahhh')
    def hot(self):
        print('ouch!')
    temp_dispatch = {COLD:cold, WARM:warm, HOT:hot}

tag = Tag('testing', 'Cold')
tag.process()


In python, it's frequently advantageous to use a dictionary for dispatch rather than a tower of if/elif/else.

So:

class Tag(object):
    def __init__(self, name, type):
        self.name = name
        self.type = type
        self.dispatch = {"cold":Tag.process_cold, "warm":Tag.process_warm, "hot":Tag.process_hot}

    def process(self):
        self.dispatch[type](self)

    def process_cold(self):
        # do something

    def process_warm(self):
        # do something else

    def process_hot(self):
        # do something even elser

And a small additional bit of code can build the dispatch table automatically:

def dispatchTable( klass, prefix ):
    """
    Given a class and a method prefix string, collect all methods in the class
    that start with the prefix, and return a dict mapping from the part of the 
    method name after the prefix to the method itself.

    e.g. you have a class Machine with methods opcode_foo, opcode_bar.
    create_dispatch_table( Machine, "opcode_" ) 
    yields a dict
    { "foo": Machine.opcode_foo, "bar": Machine.opcode_bar }
    """

    dispatch = {}
    for name, fun in inspect.getmembers( klass, inspect.ismethod ):
        if name.startswith(prefix):
            # print "found %s.%s"%(k.__name__,name)
            dispatch[ name.split(prefix)[1] ] = fun 

    return dispatch   
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号