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
精彩评论