Difference in Python and Ruby interactive shells

D

dmh2000

I am experimenting with the interactive interpreter environments of
Python and Ruby and I ran into what seems to be a fundamental
difference. However I may be doing something wrong in Python. Please
comment and correct me if I am wrong

In both languages, you can start up the interactive interpreter
('python' and 'irb'), load source files and do stuff, like create
objects and call their methods. When you want to change something, you
can edit those same source files outside the environment and reload
them from within the interactive environment. But, here is the
difference: with Python, when you reload the source file (module in
Python terms), it seems that your existing variables stay bound to the
implementations from the old version of the module. In Ruby, after a
reload, your existing variables point to the new implementation. At
least, that is what happens with classes and their methods. This means
that in Python, if you have an application built up interactively, with
references to objects, data structures pointing to objects, etc., you
would have to reconstruct that application to get the new
implementation. With Ruby, when you load the new implementation, you
get it immediately.

here is a simple example:

-------------------------------------------------------------------------------
Python interactive shell (python.exe)

C:\home\dh0072\rq>python
Python 2.4.2 (#67, Sep 28 2005, 12:41:11) [MSC v.1310 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.

# load a local file b.py for test

# instantiate an object and call a method
B

# edit b.py offline to change method 'p' to do something different then
reload
B

# binding of variable 'x' IS NOT changed. points to old version
BBBBB

# new instance of 'b' points to new version
-------------------------------------------------------------------------------
Ruby interactive shell (irb.exe)

C:\home\dh0072\rq>irb

# load a local file b.py for test

irb(main):001:0> load "b.rb"
=> true

# instantiate an object and call a method

irb(main):002:0> x = B.new
=> #
irb(main):003:0> x.p
B
=> nil

# edit b.py offline to change method 'p' to do something different then
reload

irb(main):004:0> load "b.rb"
=> true
irb(main):005:0> x.p
BBBB
=> nil

# binding of variable 'x' IS changed. points to new version

irb(main):006:0> y = B.new
=> #
irb(main):007:0> y.p
BBBB
=> nil

# new instance of 'b' points to new version
 
C

Claudio Grondi

dmh2000 said:
I am experimenting with the interactive interpreter environments of
Python and Ruby and I ran into what seems to be a fundamental
difference. However I may be doing something wrong in Python. Please
comment and correct me if I am wrong

In both languages, you can start up the interactive interpreter
('python' and 'irb'), load source files and do stuff, like create
objects and call their methods. When you want to change something, you
can edit those same source files outside the environment and reload
them from within the interactive environment. But, here is the
difference: with Python, when you reload the source file (module in
Python terms), it seems that your existing variables stay bound to the
implementations from the old version of the module. In Ruby, after a
reload, your existing variables point to the new implementation. At
least, that is what happens with classes and their methods. This means
that in Python, if you have an application built up interactively, with
references to objects, data structures pointing to objects, etc., you
would have to reconstruct that application to get the new
implementation. With Ruby, when you load the new implementation, you
get it immediately.
I am not fully sure it is what you are speaking about, but I mean, that
you have overlooked, that in the IDLE menu item [Shell] you have the
option to restart the shell what takes you back to the initial state.
It would be interesting to know for me here, if there is in Ruby the
option to keep the old values when starting a new run?

Claudio
here is a simple example:

-------------------------------------------------------------------------------
Python interactive shell (python.exe)

C:\home\dh0072\rq>python
Python 2.4.2 (#67, Sep 28 2005, 12:41:11) [MSC v.1310 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.

# load a local file b.py for test



# instantiate an object and call a method


B

# edit b.py offline to change method 'p' to do something different then
reload


B

# binding of variable 'x' IS NOT changed. points to old version


BBBBB

# new instance of 'b' points to new version


-------------------------------------------------------------------------------
Ruby interactive shell (irb.exe)

C:\home\dh0072\rq>irb

# load a local file b.py for test

irb(main):001:0> load "b.rb"
=> true

# instantiate an object and call a method

irb(main):002:0> x = B.new
=> #
irb(main):003:0> x.p
B
=> nil

# edit b.py offline to change method 'p' to do something different then
reload

irb(main):004:0> load "b.rb"
=> true
irb(main):005:0> x.p
BBBB
=> nil

# binding of variable 'x' IS changed. points to new version

irb(main):006:0> y = B.new
=> #
irb(main):007:0> y.p
BBBB
=> nil

# new instance of 'b' points to new version
 
S

Sybren Stuvel

dmh2000 enlightened us with:
When you want to change something, you can edit those same source
files outside the environment and reload them from within the
interactive environment. But, here is the difference: with Python,
when you reload the source file (module in Python terms), it seems
that your existing variables stay bound to the implementations from
the old version of the module.

IMO this is the only proper way of doing things. A variable points to
something in memory. When a module is reloaded, that thing in memory
is still there - because it is referenced, it does not get garbage
collected.
Ruby interactive shell (irb.exe)

C:\home\dh0072\rq>irb

# load a local file b.py for test

irb(main):001:0> load "b.rb"
=> true

# instantiate an object and call a method

irb(main):002:0> x = B.new
=> #
irb(main):003:0> x.p
B
=> nil

# edit b.py offline to change method 'p' to do something different then
reload

irb(main):004:0> load "b.rb"
=> true
irb(main):005:0> x.p
BBBB
=> nil

# binding of variable 'x' IS changed. points to new version

IMHO this is nasty. An assignment has already been performed.
Reloading some module should not (again, IMHO) change anything that
happened before it was reloaded.

Sybren
 
D

Diez B. Roggisch

In both languages, you can start up the interactive interpreter
('python' and 'irb'), load source files and do stuff, like create
objects and call their methods. When you want to change something, you
can edit those same source files outside the environment and reload
them from within the interactive environment. But, here is the
difference: with Python, when you reload the source file (module in
Python terms), it seems that your existing variables stay bound to the
implementations from the old version of the module. In Ruby, after a
reload, your existing variables point to the new implementation. At
least, that is what happens with classes and their methods. This means
that in Python, if you have an application built up interactively, with
references to objects, data structures pointing to objects, etc., you
would have to reconstruct that application to get the new
implementation. With Ruby, when you load the new implementation, you
get it immediately.

I don't know ruby enough to comment on _how_ they achieve that. But I know
python enough to tell you that your observation is correct, and perfectly
consistent with what python ususally does.

The problem here stems from the fact that in python, there are names and
values. The latter (also referred to as objects) can be bound to a name.

Now loading a module creates class-objects, and binds them under a name -
the class-name. But this name is by no means special. You can e.g. do

class Foo:
pass

Foo = 10

That will create a class that is bound to the name Foo - and the rebind that
very name to something completely different(tm).

Now creating an instance of that class creates an object, that has a
_reference_ to its class - not its name!

Which means that there is no connection to the _name_ of that class! Well,
one can get to that, because the class knows the name it was bound to when
it was created - but that is only for documentary purposes.

When reloading a module, a new class object is created. And bound to the
name same name as before - but all instances created before keep a
reference to their old class. Which makes perfect sense: in python, it is
possible to create classes individually for each instance, if one wants to
- by metaclasses, or factoryfunctions like this:

def createClass():
class Foo:
pass
return Foo

So - if that works, there is no way how one can know that this reloading of
a module is anything special.

Regards,

Diez
 
S

Steve Juranich

dmh2000 said:
I am experimenting with the interactive interpreter environments of
Python and Ruby and I ran into what seems to be a fundamental
difference. However I may be doing something wrong in Python. Please
comment and correct me if I am wrong

In both languages, you can start up the interactive interpreter
('python' and 'irb'), load source files and do stuff, like create
objects and call their methods. When you want to change something, you
can edit those same source files outside the environment and reload
them from within the interactive environment. But, here is the
difference: with Python, when you reload the source file (module in
Python terms), it seems that your existing variables stay bound to the
implementations from the old version of the module. In Ruby, after a
reload, your existing variables point to the new implementation. At
least, that is what happens with classes and their methods. This means
that in Python, if you have an application built up interactively, with
references to objects, data structures pointing to objects, etc., you
would have to reconstruct that application to get the new
implementation. With Ruby, when you load the new implementation, you
get it immediately.

This is correct. I'm a bit fuzzy on the details, so some of this might be
wrong, but here's what's going on (I'm pretty sure):

When Python loads (or reloads) a module, it encounters a `class' block,
which causes it to create a new type in memory. The instances created from
this type are bound to the type object. This means that after a reload,
your "B" class is pointing to a different object in memory. However, all
of your previous instances are still bound to the old definition (which is
still in memory, it's just not bound to the "B" name any more). As a
simple test, do 'x.__class__ is y.__class__'. This should return False.

Ruby, on the other hand, allows you to redefine classes on the fly. So when
Ruby reads a 'class' block, it's either (1) redefining a previously defined
object's definition, or (2) creating a new class with the definition in the
block.

I *think* that the reason for this is that the Python virtual machine (aka,
the interpreter) is much more efficient than the Ruby VM. So if you want
fast code, I'd stick with Python. However, if you regularly build large
applications in memory from an interactive interpreter, then perhaps Ruby
is the way for you to go. :)

Cheers.
 
M

malv

I think reload should be preceded by import.
Example:
Online code modification: upon modifying and saving mytest.py issue on
the interactive shell:
The shell should respond with "<module 'mytest' from
'/root/mytest.py'>" (NOT:mytest.pyc)

Note that modules importing mytest should not use 'import * from
mytest' but 'import mytest';
This requires qualifying all objects as mytest.obj
 
A

Alex Martelli

Michele Simionato said:
You want this recipe from Michael Hudson:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/160164

"automatically upgrade class instances on reload()"

Note that the version in the printed Cookbook (2nd edition) was
substantially enhanced (mostly by me and Michael working together), I
don't know if Michael updated his ASPN recipe to reflect that but at any
rate you can download all the code from the printed Cookbook as a
zipfile from O'Reilly's site (sorry, I don't recall the URL).


Alex
 
L

Lou Pecora

"Michele Simionato said:
You want this recipe from Michael Hudson:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/160164

"automatically upgrade class instances on reload()"


Impressive, but YIKES, there ought to be a simpler way to do this. I
think during the development phase editing and reloading would be very
common and you'd want everything updated. So why is it done the other
way, the reference stays the same? Is that useful? Maybe time for a
'switch' to set in Python to choose which behavior you want.

-- Lou Pecora (my views are my own) REMOVE THIS to email me.
 
S

Sybren Stuvel

Lou Pecora enlightened us with:
Impressive, but YIKES, there ought to be a simpler way to do this.
I think during the development phase editing and reloading would be
very common and you'd want everything updated.

I hardly ever reload stuff manually during development. I write a
script, and execute it. The few times I use reload() it's no big deal
to do x = B().
So why is it done the other way, the reference stays the same? Is
that useful?

It's predictable. Variables point to one and the same thing, unless
you manipulate them directly.
Maybe time for a 'switch' to set in Python to choose which behavior
you want.

That wouldn't be pythonic. People would start using that switch in
their programs too, causing a single command to act differently in
each program.

Sybren
 
D

dmh2000

Thanks all for the responses. Extra kudos to Steve J and Michele S.
that cleared it up for me.

the context of my question comes from reading up on Lisp in "Loving
Lisp - the Savy Programmer's Secret Weapon",
http://www.markwatson.com/opencontent/lisp_lic.htm, where the author
described building up a large system during test, that took a long to
to load. He was showing one reason why a dynamic language was more
productive than a statically compiled language.
 
P

Peter Otten

Alex said:
Note that the version in the printed Cookbook (2nd edition) was
substantially enhanced (mostly by me and Michael working together), I
don't know if Michael updated his ASPN recipe to reflect that but at any
rate you can download all the code from the printed Cookbook as a
zipfile from O'Reilly's site (sorry, I don't recall the URL).

http://examples.oreilly.com/pythoncook2/cb2_examples.zip

The files are named cb2_6_21_*.py, but the book has the recipe in chapter
20.15.

Peter
 
A

Alex Martelli

Peter Otten said:
http://examples.oreilly.com/pythoncook2/cb2_examples.zip

The files are named cb2_6_21_*.py, but the book has the recipe in chapter
20.15.

Ah, yes, good point: there's an "off by one" numbering issue there, due
to the fact that the O'Reilly Safari online verbatim version of the book
numbers the preface as "1" while the printed version doesn't, so chapter
1 in the printed version is 2.something on Safari, etc.


Alex
 
N

Nick Craig-Wood

Lou Pecora said:
Impressive, but YIKES, there ought to be a simpler way to do this. I
think during the development phase editing and reloading would be very
common and you'd want everything updated.

Sorry I missed this thread...

This is what I use which is easy and works just fine. I only type it
once and then press up arrow to get it back!

import workinprogress; reload(workinprogress); del(workinprogress); from workinprogress import *

That gives you the module and all its globals rebound.
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top