`

Use of Python metaclass II - Python Enumeration

阅读更多

In my previous post, I disussesed with the reader the concept of metaclass and its internals. and in following post one usage of the python metaclass is discussed. Today another use of the metaclass will be discussed.

 

As a note, this article is inspired from this original post from stackoverflow.

 

Problem with Python and Enumeration

python does not have internal keyword for enumeration, however, with the help of metaclass and dictionary, you can create your own enuemration.

 

 

let's see two impl, one is with a enum method by which you can further create any enumeration class.

 

 

First impl: enum meta method to create enumeration classes

 

 

 

The impl 

 

# define the __metaclass__ function
def M_add_class_attr(attribs):
    def foo(name, bases, dict_):
        for v, k in attribs:
            dict_[k] = v
        return type(name, bases, dict_)
    return foo

def enum(names):
    class Foo(object):
        __metaclass__ = M_add_class_attr(enumerate(names))
    def __setattr__(self, name, value): # this make it readonly
        raise NotImplementedError
    return Foo()
 

 

 

the test code 

 

 

import unittest

from MetaClass.EnumImpl1 import M_add_class_attr, enum
class Test(unittest.TestCase):


    def test_enumImpl1_usage_example(self):
        Animal = enum(['DOG', 'CAT'])
        self.assertEqual(0, Animal.DOG)
        self.assertEqual(1, Animal.CAT)
        


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.test_enumImpl1_usage_example']
    unittest.main()
 

 

Second impl:  Enumeration Class with Symbol name

In this example, we are still going to create a animal enumeration class, and we want Animal to be a symbol rather than a variable where the client is able to reassign to.

 

 

the impl

 

class Animal(object):
    
    values = ["Horse", "Dog", "Cat"]
    
    # this is a very neat implementation
    # where you define a __metaclass__ method that 
    # has the __getattr__ override to return the index of the constants
    # that you have defined in class instance 'values'  

    class __metaclass__(type):
        def __getattr__(self, name):
            return self.values.index(name)
    
    # the above is equivalent as writting as follow.
#    class Animal_Metaclass(type):
#        def __getattr__(self, name):
#            return self.values.index(name)
#    __metaclass__ = Animal_Metaclass
 

 

the test code 

 

import unittest
from MetaClass.EnumImpl2 import Animal

class Test(unittest.TestCase):

    # though the syntax is not well recognized by the Eclispe IDE, the function works 
    # perfectly well.
    def test_enumImpl2_usage(self):
#        print Animal.Horse
        self.assertEqual(0, Animal.Horse)
        self.assertEqual(1, Animal.Dog)
        self.assertEqual(2, Animal.Cat)


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.test_enumImpl2_usage']
    unittest.main()
 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics