Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Named integers and enums

Reply
Thread Tools

Named integers and enums

 
 
Hallvard B Furuseth
Guest
Posts: n/a
 
      05-23-2004
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
 
Reply With Quote
 
 
 
 
Peter Otten
Guest
Posts: n/a
 
      05-23-2004
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

 
Reply With Quote
 
 
 
 
Shalabh Chaturvedi
Guest
Posts: n/a
 
      05-23-2004
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


 
Reply With Quote
 
Hallvard B Furuseth
Guest
Posts: n/a
 
      05-24-2004
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
 
Reply With Quote
 
Scott David Daniels
Guest
Posts: n/a
 
      05-25-2004
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
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
Hallvard B Furuseth
Guest
Posts: n/a
 
      05-25-2004
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
 
Reply With Quote
 
Steve Holden
Guest
Posts: n/a
 
      05-25-2004
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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
enums and bitfileds and signs Jason Kraftcheck C++ 2 11-16-2007 10:19 AM
Enums without identifier, enums and typedef =?utf-8?b?QXNiasO4cm4gU8OmYsO4?= C Programming 10 01-20-2007 01:20 AM
getEnclosingClass and enums ogmios01@gmail.com Java 0 02-27-2006 08:24 PM
SQL Storage, Enums, Roles and Clean Coding !!! Mr Newbie ASP .Net 10 11-22-2005 11:53 AM
enums in C and C++ Simon Elliott C++ 13 11-01-2004 10:26 AM



Advertisments