[Edu-sig] source code from SA:10648
kirby urner
kirby.urner at gmail.com
Tue Jul 20 07:00:02 CEST 2010
On Mon, Jul 19, 2010 at 6:55 PM, Tim Peters <tim.peters at gmail.com> wrote:
> [kirby urner]
>> ... here's another basic
>> question. Is there a way, after importing from __future__,
>> to revert to the "old ways" later on in the same script?
>> ...
>> I'm not saying this would ever be a good idea, just
>> wondering about possibilities...
>
> In general it's not possible. At least CPython compiles an entire
> file into bytecode before anything is executed. That's why __future__
> imports have to be the first non-trivial statements in a file: they
> can change just about anything, including the bytecode that gets
> generated.
>
> For example, here's a little program:
>
> def f():
> print x / y
>
> import dis
> dis.dis(f)
>
> That defines a tiny function, then displays the bytecode generated:
>
> 2 0 LOAD_GLOBAL 0 (x)
> 3 LOAD_GLOBAL 1 (y)
> 6 BINARY_DIVIDE
> 7 PRINT_ITEM
> 8 PRINT_NEWLINE
> 9 LOAD_CONST 0 (None)
> 12 RETURN_VALUE
>
> It's not necessary to know what any of those mean, although they
> should be pretty obvious ;-) If you change the program by putting:
>
> from __future__ import division
>
> at the top, the output changes:
>
> 4 0 LOAD_GLOBAL 0 (x)
> 3 LOAD_GLOBAL 1 (y)
> 6 BINARY_TRUE_DIVIDE
> 7 PRINT_ITEM
> 8 PRINT_NEWLINE
> 9 LOAD_CONST 0 (None)
> 12 RETURN_VALUE
>
> Note that the third operation changed, from BINARY_DIVIDE to BINARY_TRUE_DIVIDE.
>
Thank you Tim, that's uber-clear and enlightening.
I notice that in IDLE, even a shell restart (menu option) does not
reset division back to the old way.
IDLE 2.6.5
>>> 1/4
0
>>> from __future__ import division
>>> 1/4
0.25
>>> ==== RESTART ====
>>> 1/4
0.25
I also recall how special name __div__ will be triggered by default
in Python 2.6 until division is imported from __future__, then
__truediv__ gets triggered instead:
>>> class Foo (object):
def __truediv__(self, other):
print "__truediv__ triggered"
def __div__(self, other):
print "__div__ triggered"
>>> o = Foo()
>>> b = Foo()
>>> o/b
__div__ triggered
>>> from __future__ import division
>>> o/b
__truediv__ triggered
If all you've done is define __div__ for your object, that'll work
by default, until you import division, then unless you have
__truediv__ defined, you'll be getting those error messages:
>>> class Foo (object):
def __div__(self, other):
print "__div__ triggered"
>>> a = Foo()
>>> a/3
__div__ triggered
>>> from __future__ import division
>>> a/3
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a/3
TypeError: unsupported operand type(s) for /: 'Foo' and 'int'
>>> a/a
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
a/a
TypeError: unsupported operand type(s) for /: 'Foo' and 'Foo'
> This is all done before anything in the file is executed, so after
> execution begins it's too late to change any of it: the opcode will
> remain whatever was generated at the start (BINARY_DIVIDE or
> BINARY_TRUE_DIVIDE) no matter what you do while the program is
> running. After all, the instant after you import the future, it
> becomes the past, and nobody can change the past ;-)
>
I'm a little surprised that resetting the IDLE shell doesn't reset
division "back to factory". It does disappear from the namespace:
>>> dir()
['Foo', '__builtins__', '__doc__', '__name__', '__package__', 'a', 'division']
>>> ======== RESTART =======
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> division
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
division
NameError: name 'division' is not defined
>>> 1/4
0.25
Maybe it shouldn't be allowed to disappear from the namespace (del division
raises an exception) as long as its effects are enforced. That way a program
could test for it. But then I supposed there's another way.
Reading from PEP 238:
The true and floor division APIs will look for the corresponding
slots and call that; when that slot is NULL, they will raise an
exception. There is no fallback to the classic divide slot.
In Python 3.0, the classic division semantics will be removed; the
classic division APIs will become synonymous with true division.
Testing in 3.1, I see __div__ is indeed gone as a special name for
integers. Only __truediv__ ( and __floordiv__ and their =/ =//
semantics) have been retained.
__div__ may be in your code, but it's not a special name (nor is
it a mangled private function given the trailing __ prevents mangling).
Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit
(Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> class Foo (object):
def __truediv__(self, other):
print ("__truediv__ triggered")
def __div__(self, other):
print ("__div__ triggered")
>>> o = Foo()
>>> o/3
__truediv__ triggered
>>> dir(3) # showing __div__ is all gone
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__',
'__delattr__', '__divmod__', '__doc__', '__eq__', '__float__',
'__floor__', '__floordiv__', '__format__', '__ge__',
'__getattribute__', '__getnewargs__', '__gt__', '__hash__',
'__index__', '__init__', '__int__', '__invert__', '__le__',
'__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__',
'__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__',
'__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__',
'__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__',
'__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
'__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
'__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__',
'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
>>> o .__div__(3)
__div__ triggered
What's in __future__ anyway?
>>> import __future__
>>> dir(__future__)
['CO_FUTURE_ABSOLUTE_IMPORT', 'CO_FUTURE_DIVISION',
'CO_FUTURE_PRINT_FUNCTION', 'CO_FUTURE_UNICODE_LITERALS',
'CO_FUTURE_WITH_STATEMENT', 'CO_GENERATOR_ALLOWED', 'CO_NESTED',
'_Feature', '__all__', '__builtins__', '__doc__', '__file__',
'__name__', '__package__', 'absolute_import', 'all_feature_names',
'division', 'generators', 'nested_scopes', 'print_function',
'unicode_literals', 'with_statement']
Kirby
More information about the Edu-sig
mailing list