Division oddity

T

Tim Rowe

If I do from __future__ import division then eval(1/2) gives me 0.5 as
expected. But if I do print input("enter a sum: ") and enter 1/2 as
the sum I get 0 as if I hadn't done the import. I thought input was
supposed to give the same behaviour as an eval on raw input -- why the
difference here?
 
D

Denis Sarrazin

Try 1.0/2 instead of 1/2. Note that when I do eval("1/2") I get 0 not
0.5

-Denis

Le Sun, 11 Jan 2004 23:45:48 +0000, Tim Rowe
 
P

Paul Rubin

Tim Rowe said:
If I do from __future__ import division then eval(1/2) gives me 0.5 as
expected. But if I do print input("enter a sum: ") and enter 1/2 as
the sum I get 0 as if I hadn't done the import. I thought input was
supposed to give the same behaviour as an eval on raw input -- why the
difference here?

The input function is calling eval from the context of the module
where 'input' itself is defined. If you use "from __future__ import
division" in module A and have "print 3/2" in module B, the value of
3/2 in module B shouldn't be affected by the input, since module B
may depend on integer division having the old behavior.

The result is a little bit surprising at first glance though, so it
should probably be documented.
 
R

Robin Becker

[QUOTE="Paul Rubin said:
If I do from __future__ import division then eval(1/2) gives me 0.5 as
expected. But if I do print input("enter a sum: ") and enter 1/2 as
the sum I get 0 as if I hadn't done the import. I thought input was
supposed to give the same behaviour as an eval on raw input -- why the
difference here?

The input function is calling eval from the context of the module
where 'input' itself is defined. If you use "from __future__ import
division" in module A and have "print 3/2" in module B, the value of
3/2 in module B shouldn't be affected by the input, since module B
may depend on integer division having the old behavior.

The result is a little bit surprising at first glance though, so it
should probably be documented.[/QUOTE]
I get this in pythonwin with 2.3.2

PythonWin 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)]
on win32.
Portions Copyright 1994-2001 Mark Hammond ([email protected]) -
see 'Help/About PythonWin' for further copyright information.
In python I get


Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
so I guess pythonwin is broken in this respect.
 
R

Raymond Hettinger

[Tim Rowe]
[Paul Rubin[
The input function is calling eval from the context of the module
where 'input' itself is defined. If you use "from __future__ import
division" in module A and have "print 3/2" in module B, the value of
3/2 in module B shouldn't be affected by the input, since module B
may depend on integer division having the old behavior.

Right!

So, the way to get eval() to respond to the import is to pass along
the current environment:
4.5


Raymond Hettinger
 
J

Jason Mobarak

Denis said:
Try 1.0/2 instead of 1/2. Note that when I do eval("1/2") I get 0 not
0.5

Please note: "from __future__ import division", see PEP 238 which
changes the behavior of the divisino operator.

My results with Python 2.3.3:
 
P

Paul Rubin

Robin Becker said:
Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
so I guess pythonwin is broken in this respect.

Huh? you get the expected result with both python and pythonwin. Neither
one is broken. The surprising result is from input(), not eval():

$ python
Python 2.2.2 (#1, Feb 24 2003, 19:13:11)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information. expression: 1/2
0
That's because input evaluates its string in the context of a
different module which was compiled with old-style division. I don't
know of other functions that use eval like that, and input() should
be deprecated or eliminated anyway, so this isn't a big deal.
 
D

Denis Sarrazin

Thanks. I'd not realized that we could test out new changes to Python
within existing Python code. Cool.

-D
 
M

Michael Hudson

[Tim Rowe]
[Paul Rubin[
The input function is calling eval from the context of the module
where 'input' itself is defined. If you use "from __future__ import
division" in module A and have "print 3/2" in module B, the value of
3/2 in module B shouldn't be affected by the input, since module B
may depend on integer division having the old behavior.

Right!

So, the way to get eval() to respond to the import is to pass along
the current environment:
4.5

Um, that's not how it works. Off the top of my head I'm not entirely
sure why eval() respects future statements and input() does not, but
it's probably easy enough to fix, if anyone cares (I don't think I
do).

Cheers,
mwh
 
R

Robin Becker

[QUOTE="Paul Rubin said:
Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
from __future__ import division
eval('1/2') 0.5
[/QUOTE]
I guess I'm 'broken' :)
 
A

Andrew Clover

Raymond Hettinger said:
So, the way to get eval() to respond to the import is to pass along
the current environment:
4.5

You can also put a future-import in the string, allowing you to run code
with features not known until run-time (and without affecting the host
script). Of course the catch is that import is a statement, not an
expression, so you have to do it with 'exec', eg.:

expr= '9/2'
features= 'division'
scope= {}
exec 'from __future__ import %s\n__assign= (%s)'%(features,expr) in scope
print scope['__assign']

4.5

What you then *can't* do is have a future-import in the host script without
it affecting the script in the exec block.

Python 2.2+ has a much nicer way of doing it involving passing flags to the
'compile' function, which is preferable if you don't need backwards
compatibility.

Anyway, straying from the original point here.
 
T

Tim Rowe

The input function is calling eval from the context of the module
where 'input' itself is defined. If you use "from __future__ import
division" in module A and have "print 3/2" in module B, the value of
3/2 in module B shouldn't be affected by the input, since module B
may depend on integer division having the old behavior.

That makes sense, thanks.
The result is a little bit surprising at first glance though, so it
should probably be documented.

Well, the documentation for "input()" says "Equivalent to
eval(raw_input(/prompt/))". Perhaps it should say "/Usually/
equivalent...."
 
P

Peter Hansen

Tim said:
Well, the documentation for "input()" says "Equivalent to
eval(raw_input(/prompt/))". Perhaps it should say "/Usually/
equivalent...."

I remember reading that too, and just assumed that at this point
it was in fact *implemented* that way, as a simple alias. Maybe
it should be...

-Peter
 
P

Paul Rubin

Peter Hansen said:
I remember reading that too, and just assumed that at this point
it was in fact *implemented* that way, as a simple alias. Maybe
it should be...

Python has no support for macros or aliases, and it would be silly
to add some special kludge for input(). The user needs to be able
to redefine the function and so forth too.
 
P

Peter Hansen

Paul said:
Python has no support for macros or aliases, and it would be silly
to add some special kludge for input(). The user needs to be able
to redefine the function and so forth too.

Sure it does:

def input(*args):
return eval(raw_input(*args))

That's what I mean by "alias", anyway.... same as the implementation
which I understand is used for string.methodx(s) nowadays, which is
apparently just passed on to s.methodx().

-Peter
 
P

Peter Hansen

Michael said:
http://www.python.org/sf/876178

Ideas on how to write a testcase welcome.

Are there any test cases which verify behaviour both in the presence
and absence of certain "from __future__ import" statements?

My first thought would have been simply to write two test files,
one of which imports from __future__ and the other which does not,
and check that in both cases input(x) == eval(raw_input(x)).

Or is the issue how to test when the input comes from stdin? In
that case, doesn't faking sys.stdin work as usual?

-Peter
 
P

Paul Rubin

Peter Hansen said:
Sure it does:

def input(*args):
return eval(raw_input(*args))

For it to be an alias, that definition would have to be injected into
the module that input is actually called from, not run in a separate
module.

How the heck does input get at the environment of its caller, anyway?
Through the frame object chain?

I guess the obvious fix is for the future division flag to be part of
the environment, so evaling in the caller environment is done according
to the flag.

Someone has already checked a fix into sourceforge, but I haven't
looked at it and don't know if it works that way or some other way.
 
M

Michael Hudson

Paul Rubin said:
For it to be an alias, that definition would have to be injected into
the module that input is actually called from, not run in a separate
module.

The problem with doing things this way is that it's not easy to get
Python-defined functions into an extension module. Nothing deep.
How the heck does input get at the environment of its caller, anyway?
Through the frame object chain?

Yes. The function you are seeking is called
PyEval_MergeCompilerFlags.
I guess the obvious fix is for the future division flag to be part of
the environment, so evaling in the caller environment is done according
to the flag.

I'm not sure what you mean here. eval() already respects future
division, as does execfile() and compile(). input() just got
overlooked when this stuff got added (back in the 2.1 era for nested
scopes, though the details have changed intermittently over the
intervening vwersions).
Someone has already checked a fix into sourceforge, but I haven't
looked at it and don't know if it works that way or some other way.

Wouldn't checking have taken about as much time as writing the above
post? It's a very simple patch...

Cheers,
mwh
 
M

Michael Hudson

Peter Hansen said:
Are there any test cases which verify behaviour both in the presence
and absence of certain "from __future__ import" statements?
Yes.

My first thought would have been simply to write two test files,
one of which imports from __future__ and the other which does not,
and check that in both cases input(x) == eval(raw_input(x)).

Or is the issue how to test when the input comes from stdin? In
that case, doesn't faking sys.stdin work as usual?

Oh, probably...

Cheers,
mwh
 

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
474,175
Messages
2,570,944
Members
47,491
Latest member
mohitk

Latest Threads

Top