Named integers and enums

  • Thread starter Hallvard B Furuseth
  • Start date
H

Hallvard B Furuseth

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

Peter Otten

Hallvard said:
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))
DEBUG:0

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

Addition etc. will continue to return ints:
3

Peter
 
S

Shalabh Chaturvedi

Hallvard said:
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__.

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
 
H

Hallvard B Furuseth

Thanks for the answers!

Shalabh said:
(...) 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):

It works as expected with subclasses of 'int':
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'n' object has no attribute 'foo'
 
S

Scott David Daniels

Hallvard said:
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):
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__
 
H

Hallvard B Furuseth

Scott said:
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.
 
S

Steve Holden

Hallvard said:
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:
True

However, none of this tells you anything about the relationship between
object, old-style class and instances thereof:
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 'type'>

regards
Steve
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top