Named integers and enums

Discussion in 'Python' started by Hallvard B Furuseth, May 23, 2004.

  1. Is this possible without too much code?

    class Named_int(object, int):
    def __str__(self): return self.name
    __repr__ = __str__
    __slots__ = 'name'
    # This does not work:
    def __init__(self, name): self.name = name
    # ...and it would be nice to freeze the name:
    __setattr__ = __delattr__ = None

    x = Named_int(3, "foo")
    print "%s = %d" % (x, x) # print "foo = 3"

    Named_int(3, "foo") says "TypeError: an integer is required".
    I've tried other ways to specify both parameters, but no luck so far.
    BTW, this is Python2.2. I don't know if we'll be able to upgrade
    anytime soon.

    I know I could do

    class Named_int:
    def __init__(self, val, name):
    self.val, self.name = int(val), str(name)
    ...

    but then I'd need a bunch of other functions: __int__, __cmp__,
    __nonzero__, __hash__, maybe also __add__ and so on.

    Or is there another way? Currently I'm only planning to use it for is a
    C-style enum, so it's merely a bit irritating that I have to set the
    name attribute after creating the Named_int:

    import sys

    class Named_int(object, int):
    def __str__(self): return self.name
    __repr__ = __str__
    __slots__ = 'name'

    def Enum(**mapping):
    vars = sys._getframe(1).f_locals
    for name, val in mapping.items():
    val = Named_int(val)
    val.name = name
    vars[name] = val

    Enum(
    Debug = 0,
    Info = 1,
    Warning = 2,
    Error = 3,
    Critical = 4
    )

    # print "Error = 3"
    print "%s = %d" % (Error, Error)

    --
    Hallvard
     
    Hallvard B Furuseth, May 23, 2004
    #1
    1. Advertising

  2. Hallvard B Furuseth

    Peter Otten Guest

    Hallvard B Furuseth wrote:

    > Is this possible without too much code?
    >
    > class Named_int(object, int):
    > def __str__(self): return self.name
    > __repr__ = __str__
    > __slots__ = 'name'
    > # This does not work:
    > def __init__(self, name): self.name = name
    > # ...and it would be nice to freeze the name:
    > __setattr__ = __delattr__ = None
    >
    > x = Named_int(3, "foo")
    > print "%s = %d" % (x, x) # print "foo = 3"


    You need __new__() instead of __init__():

    <namedint.py>
    class Int(int):
    _all = {}
    def __new__(cls, name, value):
    try:
    return cls._all[value]
    except KeyError:
    cls._all[value] = self = int.__new__(cls, value)
    self.name = name
    return self
    def __str__(self):
    return self.name
    def __repr__(self):
    return "%s:%s" % (self, int.__str__(self))
    </namedint.py>

    >>> from namedint import *
    >>> debug, info, warn = map(Int, "DEBUG INFO WARN".split(), range(3))
    >>> debug

    DEBUG:0

    Instances are cached in _all and thus only created once per value:

    >>> Int("too late", 0)

    DEBUG:0
    >>> debug < info

    1
    >>> info + warn

    3
    >>>


    Addition etc. will continue to return ints:

    >>> info + warn

    3

    Peter
     
    Peter Otten, May 23, 2004
    #2
    1. Advertising

  3. Hallvard B Furuseth wrote:
    > Is this possible without too much code?
    >
    > class Named_int(object, int):


    It is not be possible inherit from object and int in this order. When I
    try it in 2.3, I get a TypeError. Why do you want to subclass object
    here anyway? int is already a subclass of object, so just Named_int(int)
    should be enough.

    > def __str__(self): return self.name
    > __repr__ = __str__
    > __slots__ = 'name'
    > # This does not work:
    > def __init__(self, name): self.name = name
    > # ...and it would be nice to freeze the name:
    > __setattr__ = __delattr__ = None
    >
    > x = Named_int(3, "foo")
    > print "%s = %d" % (x, x) # print "foo = 3"
    >
    > Named_int(3, "foo") says "TypeError: an integer is required".


    As others have answered, you need __new__ instead of __init__.

    <alternative example snipped>

    >
    > Or is there another way? Currently I'm only planning to use it for is a
    > C-style enum, so it's merely a bit irritating that I have to set the
    > name attribute after creating the Named_int:
    >
    > import sys
    >
    > class Named_int(object, int):
    > def __str__(self): return self.name
    > __repr__ = __str__
    > __slots__ = 'name'
    >
    > def Enum(**mapping):
    > vars = sys._getframe(1).f_locals
    > for name, val in mapping.items():
    > val = Named_int(val)
    > val.name = name
    > vars[name] = val
    >
    > Enum(
    > Debug = 0,
    > Info = 1,
    > Warning = 2,
    > Error = 3,
    > Critical = 4
    > )
    >
    > # print "Error = 3"
    > print "%s = %d" % (Error, Error)
    >


    If you don't care about the int values (but I suspect you do :), and
    need pure enums, one option is to just use plain and simple objects:

    Debug = object()
    Info = object()
    etc.

    HTH,
    Shalabh
     
    Shalabh Chaturvedi, May 23, 2004
    #3
  4. Thanks for the answers!

    Shalabh Chaturvedi wrote:
    >Hallvard B Furuseth wrote:
    >> Is this possible without too much code?
    >>
    >> class Named_int(object, int):

    >
    > (...) Why do you want to subclass object here anyway? int is already a
    > subclass of object, so just Named_int(int) should be enough.


    I didn't know that. Can't find it in the python doc either. But now I
    wonder: isinstance() says that even classic class instances are 'object'
    instances, even though they do not seem to be (since __slots__ does not
    work):

    >>> class o: __slots__ = ()

    ...
    >>> isinstance(o(), object)

    1
    >>> o().foo = True
    >>>


    It works as expected with subclasses of 'int':

    >>> class n(int): __slots__ = ()

    ...
    >>> isinstance(n(3), object)

    1
    >>> n(3).foo = True

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: 'n' object has no attribute 'foo'

    --
    Hallvard
     
    Hallvard B Furuseth, May 24, 2004
    #4
  5. Hallvard B Furuseth wrote:

    > I wonder: isinstance() says that even classic class instances are 'object'
    > instances, even though they do not seem to be (since __slots__ does not
    > work):
    > >>> class o: __slots__ = ()

    > ...
    > >>> isinstance(o(), object)

    > 1
    > >>> o().foo = True
    > >>>

    Actually __slots__ works, you just have a funny idea of what __slots__
    is _for_. __slots__ is a _storage_optimization_.

    Try this:
    class Surprise(object):
    __slots__ = ('one', '__dict__', 'two')

    x = Surprise()
    x.one = 1
    x.two = 2
    x.three = 3
    x.__dict__

    --
    -Scott David Daniels
     
    Scott David Daniels, May 25, 2004
    #5
  6. Scott David Daniels wrote:
    >Hallvard B Furuseth wrote:
    >
    >> I wonder: isinstance() says that even classic class instances are 'object'
    >> instances, even though they do not seem to be (since __slots__ does not
    >> work):
    >> >>> class o: __slots__ = ()

    >> ...
    >> >>> isinstance(o(), object)

    >> 1
    >> >>> o().foo = True
    >> >>>

    >
    > Actually __slots__ works, you just have a funny idea of what __slots__
    > is _for_. __slots__ is a _storage_optimization_.


    That's not what I mean.

    I'm wondering why isinstance() claims that instances of 'o' are
    instances of 'object', when 'o' is not declared to be a subclass of
    'object'.

    I used __slots__ to check if 'o' is a subclass of 'object' anyway, since
    __slots__ is documented to only work for new-style classes - i.e.
    classes derived from 'object'. Well, it is not. If it had been, the
    assignment to o().foo above would have failed.

    --
    Hallvard
     
    Hallvard B Furuseth, May 25, 2004
    #6
  7. Hallvard B Furuseth

    Steve Holden Guest

    Hallvard B Furuseth wrote:

    > Scott David Daniels wrote:
    >
    >>Hallvard B Furuseth wrote:
    >>
    >>
    >>>I wonder: isinstance() says that even classic class instances are 'object'
    >>>instances, even though they do not seem to be (since __slots__ does not
    >>>work):
    >>> >>> class o: __slots__ = ()
    >>> ...
    >>> >>> isinstance(o(), object)
    >>> 1
    >>> >>> o().foo = True
    >>> >>>

    >>
    >>Actually __slots__ works, you just have a funny idea of what __slots__
    >>is _for_. __slots__ is a _storage_optimization_.

    >
    >
    > That's not what I mean.
    >
    > I'm wondering why isinstance() claims that instances of 'o' are
    > instances of 'object', when 'o' is not declared to be a subclass of
    > 'object'.
    >

    Instances of o are instances of object because, I believe, everything is
    ultimately held to be an instance of object. Unless you can find an x
    such that

    isinstance(x, object)

    is false - I couldn't find such a value.

    > I used __slots__ to check if 'o' is a subclass of 'object' anyway, since
    > __slots__ is documented to only work for new-style classes - i.e.
    > classes derived from 'object'. Well, it is not. If it had been, the
    > assignment to o().foo above would have failed.
    >

    As you appear to have deduced, the purpose of __slots__ is to limit the
    keys that can be stored in the object's __dict__, and so clearly o is
    not a subclass of object. But you could have determined that directly:

    >>> class o: pass

    ....
    >>> issubclass(o, object)

    False
    >>> issubclass(int, object)

    True

    However, none of this tells you anything about the relationship between
    object, old-style class and instances thereof:

    >>> type(o)

    <type 'classobj'>
    >>> oi = O()
    >>> type(oi)

    <type 'instance'>
    >>> issubclass(oi, object)

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: issubclass() arg 1 must be a class

    Sometimes it's difficult to keep your head from exploding:

    >>> type(object)

    <type 'type'>
    >>> type(type)

    <type 'type'>

    regards
    Steve
     
    Steve Holden, May 26, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mr Newbie
    Replies:
    10
    Views:
    770
    Mr Newbie
    Nov 22, 2005
  2. Replies:
    0
    Views:
    1,479
  3. Simon Elliott

    enums in C and C++

    Simon Elliott, Oct 28, 2004, in forum: C++
    Replies:
    13
    Views:
    18,533
    Simon Elliott
    Nov 1, 2004
  4. =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=

    Enums without identifier, enums and typedef

    =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=, Jan 19, 2007, in forum: C Programming
    Replies:
    10
    Views:
    1,135
    Keith Thompson
    Jan 20, 2007
  5. Jason Kraftcheck

    enums and bitfileds and signs

    Jason Kraftcheck, Nov 15, 2007, in forum: C++
    Replies:
    2
    Views:
    425
    James Kanze
    Nov 16, 2007
Loading...

Share This Page