473,385 Members | 1,922 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,385 software developers and data experts.

decimal by default

I'm writing an application that (among other things) evaluates
mathematical expressions. The user enters strings containing literals
and names that later get evaluated using the Python interpreter. Here's
a short (very simplified) example:
from decimal import Decimal
names = dict(a=Decimal('3.625'), b=Decimal(2))
expr = '(a + 2.625) / b' # expression entered by end-user
eval(expr, names)

Traceback (most recent call last):
...
TypeError: You can interact Decimal only with int, long or Decimal data
types.

I understand why I got the error, so there's no need to explain that.
It is a requirement that the 'names' dict contains Decimal values. And
of course it's unacceptable to expect my users to enter Decimal('...')
every time they enter a non-integer number. My initial solutioin is to
use a regular expression to wrap each float value with Decimal('...')
before the expression is evaluated. But I don't like that solution for
two reasons:

1. It seems error prone and inelegant. Paraphrase: if you've got a
problem and you think "Ahh, I'll use regular expressions..." now you've
got two problems.

2. Error reporting is not as intuitive (I'm using the Python
interpreter and therefore my users see Python exceptions when their
expressions don't evaluate). After the expressions have been shot up
with all the extra Decimal junk to make them evaluate correctly they
are not nearly as recognizable (or easy to read) and the user is likely
to think "but I didn't even write that expression...where is that
Decimal('...') stuff coming from?"

Ideally I'd like to have a way to tell the interpreter to use Decimal
by default instead of float (but only in the eval() calls). I
understand the performance implications and they are of no concern. I'm
also willing to define a single global Decimal context for the
expressions (not sure if that matters or not). Is there a way to do
what I want without rolling my own parser and/or interpreter? Is there
some other alternative that would solve my problem?

Thanks,
~ Daniel

Jun 29 '06 #1
3 2160
Daniel <4d*****@gmail.com> wrote:
...
Ideally I'd like to have a way to tell the interpreter to use Decimal
by default instead of float (but only in the eval() calls). I
understand the performance implications and they are of no concern. I'm
also willing to define a single global Decimal context for the
expressions (not sure if that matters or not). Is there a way to do
what I want without rolling my own parser and/or interpreter? Is there
some other alternative that would solve my problem?


What about:

c = compile(thestring, thestring, '<eval>')

cc = new.code( ...all args from c's attributes, except the 5th
one, constants, which should instead be:
decimalize(c.co_consts)...)

i.e.

cc = new.code(c.co_argcount, c.co_nlocals, c.co_stacksize, c.co_flags,
c.co_code, decimalize(c.co_consts), c.co_names,
c.co_varnames, c.co_filename, c.co_name,
c.co_firstlineno, c.co_lnotab)

where

def decimalize(tuple_of_consts):
return tuple( maydec(c) for c in tuple_of_consts )

and

def maydec(c):
if isinstance(c, float): c = decimal.Decimal(str(c))
return c
Yeah, the new.code call IS very verbose, just because it needs to
tediously and boilerplatedly repeat every attribute as an argument, but
you can easily wrap the boilerplate in an auxiliary function and forget
about it. (If you often want to change one or two tiny thing in a code
object you probably already have a suitable auxiliary function around).

Now, you can eval(cc) [[I suggest you also explicitly pass dictionaries
for locals and globals, but, hey, that's just a good idea with eval in
general!-)]] and, ta-da!
Alex
Jun 29 '06 #2
Alex Martelli wrote:
What about:

c = compile(thestring, thestring, '<eval>')

cc = new.code( ...all args from c's attributes, except the 5th
one, constants, which should instead be:
decimalize(c.co_consts)...)


Wow, what an elegant solution! I had no hope that it would be this
simple. I always wondered what compile() was useful for and now I know
at least one thing. I'll try it out tomorrow. Thanks a lot Alex!

~ Daniel

Jun 30 '06 #3
Daniel <4d*****@gmail.com> wrote:
Alex Martelli wrote:
What about:

c = compile(thestring, thestring, '<eval>')

cc = new.code( ...all args from c's attributes, except the 5th
one, constants, which should instead be:
decimalize(c.co_consts)...)
Wow, what an elegant solution! I had no hope that it would be this


Heh, funny, I was originally parsing your response as ironic, because
_I_ don't think of this as elegant -- too boilerplatey (as the expansion
I showed right after dispays!)... took me a sec to see you really mean
it!-)
simple. I always wondered what compile() was useful for and now I know
at least one thing. I'll try it out tomorrow. Thanks a lot Alex!


You're welcome! And, compile is also useful for many other things, such
as any situation where you may need to run eval multiple times on the
same string of source code (typically on multiple distinct
dicts/namespaces): compile the source once, then in the loop eval the
code object (bytecode) rather than the source -- that saves time.

Also, you may do introspection on the code object -- for example, I show
in the Nutshell's 2nd ed how this lets you perform a "safe eval" -- a
way to let the user specify any Python "literal" without risking a
malicious user running arbitrary code (essentially, you refuse to eval
the code object if its co_names isn't empty -- or, you might let said
co_names possibly contain just a few names you deem "safe", such as,
say, 'sin', 'cos', 'tan', which you can get into your namespace from the
math module). Such introspection on names may also allow some further
optimization, particularly in the repeated-execution case, if there are
"well-known names" that you're able to compute "just in time" (nowadays
you can also use a special mapping to "only compute at need" the values
for the names that are actually needed).

Beyond which, we get into the realm of byecode hacks...!-)
Alex
Jun 30 '06 #4

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

Similar topics

21
by: Batista, Facundo | last post by:
Here I send it. Suggestions and all kinds of recomendations are more than welcomed. If it all goes ok, it'll be a PEP when I finish writing/modifying the code. Thank you. .. Facundo
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....
2
by: Mike in Paradise | last post by:
Can you use the DefaultValueAttribute on Decimal PropertyFields? If so what is format for setting the Default value. Thanks... Example /// <summary> /// Field: increment value ///...
3
by: Artek | last post by:
Hello, after installing .net 1.1, ASP.NET works fine, but there is a problems with extra zeros added to the numbers at the end. In Sql 2000 SP3a there is for example a table with one column ...
1
by: | last post by:
eg. "19.121" to 19.12 decimal eg. "12.567 " to 12.56 decimal
1
by: invinfo | last post by:
keywords: mysql accounting currency decimal fixed "floating point" Quoting the manual: DECIMAL)] If D is omitted, the default is 0. If M is omitted, the default is 10. All basic calculations...
3
by: Boot2TheHead | last post by:
This one cost me a solid half hour yesterday. I'm wondering why on earth the default precision for a decimal type is 18,0. Maybe I'm mistaken. A decimal datatype sort of implies that you'd want...
23
by: neha_chhatre | last post by:
which is the best format specifier(data type) if i have to work with decimal number. also please tell me the syntax for truncating a decimal number please reply as soon as possible
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)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 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 former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
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
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

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.