String vs. Enum для проверки типа объекта в Python - PullRequest
1 голос
/ 27 сентября 2011

Скажем, у меня есть объект с именем Tag, и у меня есть три типа тегов, как указано в переменной экземпляра следующим образом,

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")

Допустим, я допустил только три типа: холодный, теплый и горячий. Было бы лучше пойти проверить, относится ли это к одному из этих типов?

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

Или я должен создать объект типа enum, подобный этому из question ,

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

И вместо этого создать теги, как это?

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

Причина, по которой я задаю этот вопрос, заключается в том, что я слышал, что много вычислительной мощности уходит на сравнение строк, и, хотя это короткие слова длиной 3, 4 буквы, возможно, что я проведу десятки тысяч сравнений из этих типов. Как вы думаете, стоит ли создавать объекты enum для определения типа объекта, как в приведенном выше примере? Или есть лучший способ сделать то, что я пытаюсь сделать?

Ответы [ 4 ]

2 голосов
/ 27 сентября 2011

Я бы не беспокоился о производительности этого, если профилирование не показывает, что это действительно проблема. Если вы используете IDE, метод enum имеет преимущество проверки типов.

2 голосов
/ 27 сентября 2011

Возможно, разница в производительности может быть недостаточной, чтобы вы беспокоились об этом. Вы должны сделать простой тест, если вы беспокоитесь о производительности. Используйте модуль Python timeit для проверки производительности обоих случаев.

1 голос
/ 27 сентября 2011

Я бы выбрал комбинированный подход - пусть enum будет частью класса Tag, примет строку для инициализации, а затем преобразует ее.Кроме того, вместо использования множества веток if / else вы можете использовать dict для создания таблицы отправки.

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()
0 голосов
/ 27 сентября 2011

В python часто выгодно использовать словарь для отправки, а не букву if / elif / else.

Итак:

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

И небольшой дополнительный бит кодаможет построить таблицу отправки автоматически:

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   
...