python enumeration class for ORM purposes

后端 未结 3 2007
-上瘾入骨i
-上瘾入骨i 2021-01-20 00:49

EDITED QUESTION

I\'m trying to create a class factory that can generate enumeration-like classes with the following properties:

  1. Class
相关标签:
3条回答
  • 2021-01-20 01:26

    Maybe this enumeration function from the Verse Quiz program could be of some use to you: Verse Quiz

    0 讨论(0)
  • 2021-01-20 01:29

    You can create new classes on-the-fly with the type builtin:

    type(name, bases, dict)

    Return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the __dict__ attribute. For example, the following two statements create identical type objects:

    >>> class X(object):
    ...     a = 1
    ...
    >>> X = type('X', (object,), dict(a=1))
    
    New in version 2.2.
    

    In this case:

    genre_mapping = { }
    for genre in { 'scifi', 'romance', 'comic', 'science' }:
        genre_mapping[ 'genre' ] = type( genre, ( Genre, ), { } )
    

    or in Python 2.7+:

    genre_mapping = { genre: type( genre, ( Genre, ), { } ) for genre in genres }
    

    If you are doing this a lot, you can abstract away the pattern.

    >>> def enum( cls, subs ):
    ...     return { sub: type( sub, ( cls, ), { } ) for sub in subs }
    ...
    >>> enum( Genre, [ 'scifi', 'romance', 'comic', 'science' ] )
    {'romance': <class '__main__.romance'>, 'science': <class '__main__.science'>,
    'comic': <class '__main__.comic'>, 'scifi': <class '__main__.scifi'>}
    

    EDIT: Have I missed the point? (I've not used SQLAlchemy before.) Are you asking how to create new subclasses of Genre, or how to create new instances? The former seems intuitively right, but the latter is what you've asked for. It's easy:

    list( map( Genre, [ 'scifi', ... ] ) )
    

    will make you a list of:

    [ Genre( 'scifi' ), ... ]
    
    0 讨论(0)
  • 2021-01-20 01:32

    new answer based on updates

    I think that this satisfies all of your specified requirements. If not, we can probably add whatever you need.

    def enum(classname, values):
        class EnumMeta(type):
            def __iter__(cls):
                return cls._instances.itervalues()
    
        class EnumType(object):
            __metaclass__ = EnumMeta
            _instances = {}
            _next_id = 0
            def __init__(self, value):
                self.value = value
                self.id = type(self)._next_id
                type(self)._next_id += 1
    
            def instance(self, value):
                return type(self)._instances[value]
    
        cls = type(classname, (EnumType, ), {})
        instances = dict((value, cls(value)) for value in values)
        cls._instances = instances
    
        def __new__(cls, value):
            raise TypeError('No more instances allowed')
    
        cls.__new__ = staticmethod(__new__)
        return cls
    
    
    Genre = enum('Genre', ['scifi', 'comic', 'science'])
    
    
    for item in Genre:
        print item, item.value, item.id
        assert(item is Genre(item.value))
        assert(item is item.instance(item.value))
    
    Genre('romance')
    

    old answer

    In response to your comment on Noctis Skytower's answer wherein you say that you want Genre.comic = Genre('comic') (untested):

    class Genre(GenreBase):
        genres = ['comic', 'scifi', ... ]
        def __getattr__(self, attr):
            if attr in type(self).genres:
                self.__dict__[attr] = type(self)(attr)
            return self.__dict__[attr]
    

    This creates an instance of genre in response to an attempt to access it and attaches it to the instance on which it is requested. If you want it attached to the entire class, replace the line

    self.__dict__[attr] == type(self)(attr) 
    

    with

    type(self).__dict__[attr] = type(self)(attr)
    

    this has all subclasses create instances of the subclass in response to requests as well. If you want subclasses to create instances of Genre, replace type(self)(attr) with Genre(attr)

    0 讨论(0)
提交回复
热议问题