Python 中检查对象类型的字符串与枚举

发布于 2024-12-06 12:03:03 字数 884 浏览 2 评论 0原文

假设我有一个名为 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

或者我应该创建一个类似枚举的对象,例如 问题

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

而是创建这样的标签?

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

我问这个问题的原因是因为我听说比较字符串需要大量的处理能力,即使这些是 3、4 个字母长的单词,我也可能会对这些类型进行数万次比较。您认为像上面所示的示例中那样创建枚举对象来确定对象的类型值得吗?或者有更好的方法来做我想做的事情吗?

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 comparisons 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冰葑 2024-12-13 12:03:03

性能差异可能不足以让您担心。如果您担心性能,您应该进行一个简单的测试。使用Python的timeit模块来测试这两种情况的性能。

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.

猫卆 2024-12-13 12:03:03

我不会担心它的性能,除非分析表明它确实是一个问题。如果您使用 IDE,则枚举方法具有拼写错误检查的优点。

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.

像你 2024-12-13 12:03:03

我会采用组合方法 - 让“枚举”成为 Tag 类的一部分,接受字符串进行初始化,然后将其转换。此外,您可以使用字典来创建调度表,而不是使用一堆 if/else 分支。

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

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()
梦萦几度 2024-12-13 12:03:03

在 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   

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   
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文