473,397 Members | 1,974 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

Decimal, __radd__, and custom numeric types...

I'm having some issues with decimal.Decimal objects playing nice with
custom data types. I have my own matrix and rational classes which
implement __add__ and __radd__. They know what to do with Decimal
objects and react appropriately.

The problem is that they only work with Decimals if the custom type is
on the left (and therefore __add__ gets called), but NOT if the Decimal
is on the left. The Decimal immediately throws the usual "TypeError:
You can interact Decimal only with int, long or Decimal data types."
without even trying my __radd__ method to see if my custom type can
handle Decimals.
From the Python docs (specifically sections 3.3.7 and 3.3.8), I thought

that the left object should try its own __add__, and if it doesn't know
what to do, THEN try the right object's __radd__ method. I guess
Decimal objects don't do this? Is there a way to change this behavior?
If Decimal objects prematurely throw a TypeError before trying the
__rop__, is Decimal broken, or was it designed this way? I think I'm
missing something...

Thanks,
Blake

Jul 18 '05 #1
7 2006
Blake T. Garretson <bl*************@gmail.com> wrote:
I'm having some issues with decimal.Decimal objects playing nice with
custom data types. I have my own matrix and rational classes which
implement __add__ and __radd__. They know what to do with Decimal
objects and react appropriately.

The problem is that they only work with Decimals if the custom type is
on the left (and therefore __add__ gets called), but NOT if the Decimal
is on the left. The Decimal immediately throws the usual "TypeError:
You can interact Decimal only with int, long or Decimal data types."
without even trying my __radd__ method to see if my custom type can
handle Decimals.

From the Python docs (specifically sections 3.3.7 and 3.3.8), I thought
that the left object should try its own __add__, and if it doesn't know
what to do, THEN try the right object's __radd__ method. I guess
Decimal objects don't do this? Is there a way to change this behavior?
If Decimal objects prematurely throw a TypeError before trying the
__rop__, is Decimal broken, or was it designed this way? I think I'm
missing something...


It looks like from reading 3.3.8 if decimal raised a NotImplemented
exception instead of a TypeError then it would work.

For objects x and y, first x.__op__(y) is tried. If this is not
implemented or returns NotImplemented, y.__rop__(x) is tried. If
this is also not implemented or returns NotImplemented, a
TypeError exception is raised. But see the following exception:

Exception to the previous item: if the left operand is an instance
of a built-in type or a new-style class, and the right operand is
an instance of a proper subclass of that type or class, the right
operand's __rop__() method is tried before the left operand's
__op__() method. This is done so that a subclass can completely
override binary operators. Otherwise, the left operand's __op__
method would always accept the right operand: when an instance of
a given class is expected, an instance of a subclass of that class
is always acceptable.

You could try this with a local copy of decimal.py since it is
written in Python.

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #2
On 28 Feb 2005 12:11:33 -0800, "Blake T. Garretson"
<bl*************@gmail.com> wrote:

[...]
From the Python docs (specifically sections 3.3.7 and 3.3.8), I thought
that the left object should try its own __add__, and if it doesn't know
what to do, THEN try the right object's __radd__ method.
To me it reads more like the interpreter is responsible for picking
which method to call. Specifically, section 3.3.8 of the reference
manual states that y.__rop__() will be called if x.__op__() is not
implemented or returns NotImplemented. The decision to call
y.__rop__() is made outside the x.__op__() method, implying that
x.__op__() doesn't handle a call to y.__rop__() in this case. The
other rules dealing with whether x.__op__() or y.__rop__() is called
don't apply to your situation (but they could, keep reading).
I guess
Decimal objects don't do this? Is there a way to change this behavior?
If Decimal objects prematurely throw a TypeError before trying the
__rop__, is Decimal broken, or was it designed this way? I think I'm
missing something...

You could change the behavior of Decimal.__add__ by patching it or you
could use subclassing. If your classes are subclasses of Decimal,
their __rop__ methods will be called before Decimal.__op__ is tried.
I'm guessing your matrix and rational classes don't use decimal
representation, which makes this an OOP style-breaking kludge.

Jul 18 '05 #3
Blake T. Garretson wrote:
If Decimal objects prematurely throw a TypeError before trying the
__rop__, is Decimal broken, or was it designed this way?


I suspect the former, since I can't recall this subject coming up at any point
during the PEP approval or implementation process. And I was one of the people
who worked on it before 2.4 was released :)

So I'd suggest:

a) Checking that replacing the relevant "raise TypeError" calls in
Lib/Decimal.py with "return NotImplemented" gives you friendlier behaviour.

b) Filing a bug report on SF

I'll be bringing the question up on py-dev as well.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #4
Nick Coghlan wrote:
a) Checking that replacing the relevant "raise TypeError" calls in
Lib/Decimal.py with "return NotImplemented" gives you friendlier behaviour.


It turns out this isn't really practical - there's too much code in the module
relying on those TypeErrors being raised.

So this may change for Python 2.5 (I think it's a genuine bug), but you're
probably stuck with it for 2.4 (since changing it is a big enough semantic
change to break code in the same module, so who knows what it would do to user
code).

Bugger :(

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #5
Nick Coghlan wrote:
Nick Coghlan wrote:
a) Checking that replacing the relevant "raise TypeError" calls in
Lib/Decimal.py with "return NotImplemented" gives you friendlier
behaviour.

It turns out this isn't really practical - there's too much code in the
module relying on those TypeErrors being raised.


Then again, maybe it's not so bad:

Py> class C:
.... def __add__(self, other):
.... print "OK!"
.... __radd__ = __add__
....
Py> x = decimal.Decimal()
Py> C() + x
OK!
Py> x + C()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "C:\Python24\lib\decimal.py", line 906, in __add__
other = _convert_other(other)
File "C:\Python24\lib\decimal.py", line 2863, in _convert_other
raise TypeError, "You can interact Decimal only with int, long or Decimal da
ta types."
TypeError: You can interact Decimal only with int, long or Decimal data types.

Py> x = friendly_decimal.Decimal()
Py> C() + x
OK!
Py> x + C()
OK!

Cheers,
Nick.
http://boredomandlaziness.skystorm.n...dly_decimal.py

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #6
Thanks for the suggestions and modified module. I will probably just
use this "fixed" module to solve my immediate problem. I appreciate
your post to python-dev as well; it looks like this may be addressed in
a future release. :)

Thanks,
Blake

Jul 18 '05 #7
Blake T. Garretson wrote:
Thanks for the suggestions and modified module. I will probably just
use this "fixed" module to solve my immediate problem.


Expect its performance to be worse than the standard version - it does the right
thing, but it sure ain't pretty. . .

Cheers,
Nick.
--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: John Bentley | last post by:
John Bentley: INTRO The phrase "decimal number" within a programming context is ambiguous. It could refer to the decimal datatype or the related but separate concept of a generic decimal number....
3
by: Mark | last post by:
I have a Decimal or a Double - your choice. I'd like to print the number as string with a specified number of decimal places. Let's say my number 110.5, and I'd like to capture it in a string...
3
by: JenHu | last post by:
Hi all, I have to read from a text file and generate values and insert to database. But first of all, when the text file contains '0000000000', I received a sEfundAmt value = 0D instead of 0.0...
11
by: Pieter | last post by:
Hi, I'm having some troubles with my numeric-types in my VB.NET 2005 application, together with a SQL Server 2000. - I first used Single in my application, and Decimal in my database. But a...
12
by: Frank Millman | last post by:
Hi all I have a standard requirement for a 'decimal' type, to instantiate and manipulate numeric data that is stored in a database. I came up with a solution long before the introduction of the...
2
hyperpau
by: hyperpau | last post by:
Before anything else, I am not a very technical expert when it comes to VBA coding. I learned most of what I know by the excellent Access/VBA forum from bytes.com (formerly thescripts.com). Ergo, I...
7
by: Andrus | last post by:
How to create format string for decimal data type which shows blank for zero and default format otherwize ? I tried format string "f;f;#" but this shows f for nonzero numbers. Andrus. ...
17
by: D'Arcy J.M. Cain | last post by:
I'm not sure I follow this logic. Can someone explain why float and integer can be compared with each other and decimal can be compared to integer but decimal can't be compared to float? True...
6
by: Terry Reedy | last post by:
Gerhard Häring wrote: The new fractions module acts differently, which is to say, as most would want. True Traceback (most recent call last): File "<pyshell#20>", line 1, in <module> F(1.0)...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.