Mixing Decimal and float

B

B.V.

Hi,

In order to solve some issues due to operations between Decimal and
float, we wanted to implement a class that inherits from both float
and Decimal.

Typically, we wrote:
class Float(Decimal, float):
....

This can not be achieved because of a TypeError exception (with
message "multiple bases have instance lay-out conflict").

With a class that inherits from Decimal, with overridden __add__,
__mul__, .... , we succeed to solve operations issues.

But we also need to do:
isinstance(Float('1'), float) == True
isinstance(Float('1'), Decimal) == True
which is, AFAIK, only possible with Float(Decimal, float).

Is there a workaround ?

We are developping with python version 2.5 and 2.6.

Thanks for your help.

B.
 
M

Mark Dickinson

Hi,

In order to solve some issues due to operations between Decimal and
float, we wanted to implement a class that inherits from both float
and Decimal.

Typically, we wrote:

class Float(Decimal, float):

Can you explain exactly what issues you want to solve, and how you
want your Float class to behave? Do I understand correctly that you
want your Float class to be able to represent both floats and
Decimals?
But we also need to do:
isinstance(Float('1'), float) == True
isinstance(Float('1'), Decimal) == True

Can you explain why you need this?

Should isinstance(Float('1.1'), float) and isinstance(Float('1.1'),
Decimal) also both be true, or would only one of those be true? (And
by the way, what value would Float('1.1') have? float('1.1') and
Decimal('1.1') are different values.)

I don't think your approach can succeed; I'd suggest just subclassing
'object' and abandoning the 'isinstance' requirements. Or perhaps
creating a subclass of Decimal that interacts nicely with floats. You
might also want to investigate the numbers ABC, though that's new in
Python 2.6.
 
B

B.V.

Can you explain exactly what issues you want to solve, and how you
want your Float class to behave?  Do I understand correctly that you
want your Float class to be able to represent both floats and
Decimals?

Let me give you the whole story. We work on Tryton, an client/server
application framework written in Python (http://www.tryton.org).
The framework defines several types of fields within its own ORM
(http://doc.tryton.org/1.6/trytond/doc/ref/models/fields.html#ref-
models-fields); among those types, there's a fields.Float type -- not
to be confused with the class Float we are talking about -- (with
underlying python type float) and fields.Numeric (with underlying
python type Decimal).
fields.Numeric(Decimal) where implemented at the beginning of the fork
(Tryton is a fork of OpenERP, formerly known as TinyERP), because the
use of floats in OpenERP leads many problems in module handling
financial data.

The client is written in pygtk. The client connects the server through
a specific (but simple) protocol called pysocket (roughly pickled data
over sockets).
In an application, you may define objects with both Numeric or Float
attributes, and when you need to make them interact, you have to cast.
And everything is fine.

But trying to be open to other languages, the server implements also
an XMLRPC interface (and also a JSONRPC-like interface). That's the
key point: Decimal is python specific. So in an application, you can't
rely on the value received from a client, because depending on the
protocol, the type of the value is different.
So the idea was to create a class that can behave like a Decimal or a
float depending on the context, and set
xmlrpclib.Unmarshaller.dispatch["double"] to a function that return a
Float instance.

A contributor filed an issue on the bug tracker (https://
bugs.tryton.org/roundup/issue1575) and because he's a nice guy (ok
it's a friend of mine), he made a patch proposal (http://
codereview.appspot.com/1387041). The end of the story is in the
comments of the proposal.
Can you explain why you need this?

It's a requirement of the project leader.
Should isinstance(Float('1.1'), float) and isinstance(Float('1.1'),
Decimal) also both be true, or would only one of those be true?  (And
by the way, what value would Float('1.1') have?  float('1.1') and
Decimal('1.1') are different values.)

I think they both should be True, for '1', '1.1', '0', '0.1', ...
For the value, I would say that it depends of the definition of the
field (fields.Float or fields.Numeric).

I don't think your approach can succeed;  I'd suggest just subclassing
'object' and abandoning the 'isinstance' requirements.  Or perhaps
creating a subclass of Decimal that interacts nicely with floats.  You
might also want to investigate the numbers ABC, though that's new in
Python 2.6.

First, Float implementation was a subclass of Decimal that works with
floats, and solves many (maybe all) problems. But as you may read in
the comments of the patch proposal, it seems to be not enough.

B.
 
T

Terry Reedy

A contributor filed an issue on the bug tracker (https://
bugs.tryton.org/roundup/issue1575) and because he's a nice guy (ok
it's a friend of mine), he made a patch proposal (http://
codereview.appspot.com/1387041). The end of the story is in the
comments of the proposal.

I have no idea how to do what you want. But for future reference, links
put in running email/newsgroup text as above are not very usable for
most readers. They are best put on a line *by themselves*. Then they can
be clicked on in at least some mail/newsgroup readers, or at worst,
copied and pasted to a browser. Reformatted to be more usable:

A contributor filed an issue on the bug tracker
https://bugs.tryton.org/roundup/issue1575
and because he's a nice guy (ok
it's a friend of mine), he made a patch proposal
http://codereview.appspot.com/1387041
The end of the story is in the comments of the proposal.

Terry Jan Reedy
 
B

B.V.

I have no idea how to do what you want. But for future reference, links
put in running email/newsgroup text as above are not very usable for
most readers. They are best put on a line *by themselves*. Then they can
be clicked on in at least some mail/newsgroup readers, or at worst,
copied and pasted to a browser. Reformatted to be more usable:

A contributor filed an issue on the bug trackerhttps://bugs.tryton.org/roundup/issue1575
and because he's a nice guy (ok
it's a friend of mine), he made a patch proposalhttp://codereview.appspot.com/1387041
The end of the story is in the comments of the proposal.

Terry Jan Reedy

Thank you for your remarks, my next posts will in accordance.

B.
 
N

Nathan Rice

My apologies if someone already mentioned this and I missed it but...

class.__instancecheck__(self, instance) - Return true if instance
should be considered a (direct or indirect) instance of class. If
defined, called to implement isinstance(instance, class).

class.__subclasscheck__(self, subclass) - Return true if subclass
should be considered a (direct or indirect) subclass of class. If
defined, called to implement issubclass(subclass, class).

Nathan
 
S

Steven D'Aprano

My apologies if someone already mentioned this and I missed it but...

class.__instancecheck__(self, instance) - Return true if instance should
be considered a (direct or indirect) instance of class. If defined,
called to implement isinstance(instance, class).

class.__subclasscheck__(self, subclass) - Return true if subclass should
be considered a (direct or indirect) subclass of class. If defined,
called to implement issubclass(subclass, class).

The original poster needs to support Python 2.5 and 2.6, but
__instancecheck__ and __subclasscheck__ are only supported in 2.6 or
higher, so this doesn't help.
 
C

Chris Rebert

The original poster needs to support Python 2.5 and 2.6, but
__instancecheck__ and __subclasscheck__ are only supported in 2.6 or
higher, so this doesn't help.

Even in 2.6+, good luck trying to define new methods on class `type`
(the metaclass of float and Decimal).

Cheers,
Chris
 
B

B.V.

Even in 2.6+, good luck trying to define new methods on class `type`
(the metaclass of float and Decimal).

Cheers,
Chris
--http://blog.rebertia.com

You mean it! I have spent two hours trying it, with no success. I
think we manage to find another solution to our problem.
Thank you for helping.

B.
 
B

B.V.

But trying to be open to other languages, the server implements also an
XMLRPC interface (and also a JSONRPC-like interface). That's the key
point: Decimal is python specific. So in an application, you can't rely
on the value received from a client, because depending on the protocol,
the type of the value is different. So the idea was to create a class
that can behave like a Decimal or a float depending on the context, and
set xmlrpclib.Unmarshaller.dispatch["double"] to a function that return
a Float instance.

Looking at the Tryton docs, it seems that it already supports field types
that can't be directly represented in XMLRPC or JSON, like BigInteger or
Selection. How are these serialized over the non-python RPC mechanisms?
Could you not do the same for Decimals?

That's what was done first, it works for data sent by the server. But
when the server receives data, it's always float. How guess that a
float has to stay a float or became a Decimal ?
Well, Selection are just strings, no problem over any RPC mechanisms.
For the BigInteger, good question. Maybe there's a problem with,
because AFAIK it's not used in any of the classes. I think I give it a
try and who knows, maybe find a new bug ...

B.
 

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,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top