Re: finding name of instances created

2005-01-24 Thread Nick Coghlan
Steven Bethard wrote:
That is, you can just keep track of all the names of a Robot in the 
Robot object.  In the simple case, where there's only one name, you can 
display it as such.  In the more complicated case, where there's some 
aliasing, you can display the multiple aliases.  This means you don't 
have to teach about aliasing right off the bat, but if a student 
accidentally discovers it on their own, the machinery's there to explain 
it...
Incidentally, this discussion made me realise the real reason why using a lambda 
to create a named function is evil:

Py def f(): pass
...
Py f.func_name
'f'
Py f = lambda: None
Py f.func_name
'lambda'
I think I've heard that explanation before, but it never really clicked.
Cheers,
Nick.
--
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
http://boredomandlaziness.skystorm.net
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-24 Thread Fredrik Lundh
Nick Coghlan wrote:

 Incidentally, this discussion made me realise the real reason why using a 
 lambda to create a named 
 function is evil:

 Py def f(): pass
 ...
 Py f.func_name
 'f'
 Py f = lambda: None
 Py f.func_name
 'lambda'

 I think I've heard that explanation before, but it never really clicked.

that's nothing you cannot fix, though:

 f = lambda: None
 f.func_name = f

 f.func_name
'f'

(only works in 2.4 and later, from what I can tell)

/F 



-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-24 Thread Antoon Pardon
Op 2005-01-24, Nick Coghlan schreef [EMAIL PROTECTED]:
 Steven Bethard wrote:
 That is, you can just keep track of all the names of a Robot in the 
 Robot object.  In the simple case, where there's only one name, you can 
 display it as such.  In the more complicated case, where there's some 
 aliasing, you can display the multiple aliases.  This means you don't 
 have to teach about aliasing right off the bat, but if a student 
 accidentally discovers it on their own, the machinery's there to explain 
 it...

 Incidentally, this discussion made me realise the real reason why using a 
 lambda 
 to create a named function is evil:

It is not a named function, it is just a lamda that is assigned to a
name.

 Py def f(): pass
 ...
 Py f.func_name
 'f'
 Py f = lambda: None
 Py f.func_name
 'lambda'

 I think I've heard that explanation before, but it never really clicked.

I just don't see what is so evil about it.

Why is it so trouble some that a function wouldn't have a name, while
most objects don't have a name. Why is it a problem doing something
like:

   f = lambda: None

But isn't it a problem doing something like

   v = None.


Why don't we demand something like

   Py assign v: None
   Py v.obj_name
   'v'

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-24 Thread André

Ryan Paul wrote:
 On Mon, 24 Jan 2005 13:19:45 +, Ryan Paul wrote:

 
  A working solution:
 
  class A:
pass
 
  a = A()
  b = A()
  c = A()
 
  [x for x,y in locals().items() if
hasattr(y,__class__) and y.__class__ == A]
 

 Just wanted to clarify, because I know that the intellectually
deficient
 amongst you will say that isinstance is better than using
__class__...

 In this case isinstance isnt desirable because it will catch
 instances of any objects that inherit A, not just instances of A.
Observe:

 class A: pass
 class B(A): pass

 a = A()
 b = A()
 c = A()
 d = B()

  [x for x,y in locals().items() if isinstance(y,A)]
 ['a', 'c', 'b', 'd']

  [x for x,y in locals().items() if
 ... hasattr(y,__class__) and y.__class__ == A]
 ['a', 'c', 'b']

Actually, it this case, isinstance *is* desirable (or rather *would
have been*), exactly for the reason that you point out.  After teaching
about objects, one of the next subject would be that of inheritance.
E.G.

class BetterRobot(Robot):
...  # create a robot that can turn right directly...

However, I have been convinced that it would be much truer to Python to
give the robot fake names (robot1, robot2, ...), and then have students
name their own robots through declarations like:

cleese = Robot(name=Cleese)

or
cleese = Robot()
cleese.name = Cleese
=
André
 
 -- SegPhault

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-24 Thread Ryan Paul
On Fri, 21 Jan 2005 16:13:19 -0800, André wrote:

 Short version of what I am looking for:
 
 Given a class public_class which is instantiated a few times e.g.
 
 a = public_class()
 b = public_class()
 c = public_class()
 
 I would like to find out the name of the instances so that I could
 create a list of them e.g.
 ['a', 'b', 'c']
 


A working solution:

class A:
  pass

a = A()
b = A()
c = A()

[x for x,y in locals().items() if
  hasattr(y,__class__) and y.__class__ == A]

That said, you probably dont want to do it. I doubt that it will work
consistently.

BTW, based on my understanding of the other stuff you said, this is
probably not the best way to do whatever it is you are trying to do.

--SegPhault




-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-23 Thread André

Nick Coghlan wrote:
 André wrote:
  So, students will be able to write:
  pete = CreateRobot(2, 3)
  pete.move()
 
  learning about objects and methods.
 
  As for things like
  for robot in robots:
  do stuff
 
  that will be for my use only: drawing robots on the screen,
updating
  the 'world' when robots pick stuff up, etc.  My intention is that
the
  students will use the EXACT python syntax, so that they don't know
that
  *I* have given a *name* to their robot(s) behind the scene.
  I have to cut this short; I hope it clarifies my intentions.

 My (and, if I understand him correctly, Jeremy's) concern would be
that error
 messages like Robot 'pete' has hit a wall! would give students the
impression
 that the robots automatically know their name as a result of the
assignment. In
 standard Python, that simply isn't true.


It was not my intention to reveal that I had assigned a 'name' to the
robot; it was only for internal purpose.(However, see below)

 If, instead, CreateRobot looked something like:

 def CreateRobot(street, avenue, name=None):
if name is None:
  name = Robot + Robot.getNextNumber()
return Robot(street, avenue, name)


 Then, using a simple assignment:

 pete = CreateRobot(2, 3)
 pete.move()

 Would give an error like:

 Robot1 has hit a wall

That might be an excellent way to solve my problem.


 This could then be used to point out that objects named using
assignment don't
 know about the names they have been given, and need to be told:

 pete = CreateRobot(2, 3, Pete)
 pete.move()

 Pete has hit a wall

 Instead of misleading the students (objects know what names they
have been
 given), you have taught them a powerful truth - objects and the
names you give
 them via assignment are entirely independent.

Good point.


 It also directly addresses the question of aliasing. Think about how
Steven's
 modified dictionary would react to this code:

 pete = CreateRobot(2, 3)
 dad = pete
 dad.move()
 pete.move()

 Internally, idioms like for robot in robots should be entirely
unaffected -
 the registration of the robot instance with the global list of robots
can be
 handled by the robot initialisation method.


You make some excellent points.  What I implemented (last night) was
the code pre-processing suggestion.  Instead of simply executing
the code, I changed it first so that statements like

pete = CreateRobot(2, 3)
john = CreateRobot()
albert = CreateRobot(colour=blue)

get translated to

pete = CreateRobot(2, 3, name=pete)
john = CreateRobot(name=john)
albert = CreateRobot(colour=blue, name=albert)

I just checked with:

pete = CreateRobot()
dad = pete
dad.move()
pete.move()

and I got (I haven't implemented the gui part of dealing with multiple
robots)
==
robot pete move()
robot pete move()
==
which worked the same way as your method would (except with pete as a
common name instead of Robot1).

[As an aside, it was an *interesting* experience to learn enough about
regular expressions to do this.]

Now, after reading your post, I realise that I would have to deal with
the problem of figuring out how to handle cases where the users has
already given a name to the robot.  Your solution takes care of this in
a very simple way.

Furthermore, I could probably base a lesson around it, about how
instances have no name.
Thank you very much for your suggestions.

André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-23 Thread André

Scott David Daniels wrote:
 André Roberge wrote:
  Craig Ringer wrote:
 
  On Fri, 2005-01-21 at 16:13 -0800, André wrote:
 
  Short version of what I am looking for:
 
  Given a class public_class which is instantiated a few times
e.g.
 
  a = public_class()
  b = public_class()
  c = public_class()
 
  I would like to find out the name of the instances so that I
could
  create a list of them e.g.
  ['a', 'b', 'c']
 
  ...
  Behind the scene, I have something like:
  robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
  and have mapped move() to correspond to robot_dict['robot'].move()
  (which does lots of stuff behind the scene.)
  ...[good explanation]...
   Does this clarify what I am trying to do and why?

 Yup.  Would something like this help?

  parts = globals().copy()
  parts.update(locals())
  names = [name for name, value in parts.iteritems()
   if isinstance(value, Robot)] # actual class name here

 Note, however, that

  a = b = CreateRobot()

 will give two different names to the same robot.

 And even:

  Karl = CreateRobot()
  Freidrich = CreateRobot()
  for robot in (Karl, Freidrich):
  robot.move()

 Will have two names for Freidrich -- Freidrich and robot

 --Scott David Daniels

Thanks for your suggestion.
It might have been interesting to try, but I am going to
try and implement a suggestion given by Nick Coghlan instead.
André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-23 Thread Steven Bethard
Michael Tobis wrote:
I have a similar problem. Here's what I do:
.def new_robot_named(name,indict=globals()):
.   execstr = name +  = robot(' + name + ')
.   exec(execstr,indict)
.class robot(object):
.   def __init__(self,name):
.  self.name = name
.   def sayhi(self):
.  print Hi!  I'm %s! % self.name
.if __name__==__main__:
.   new_robot_named('Bert')
.   new_robot_named('Ernie')
.   Ernie.sayhi()
.   Bert.sayhi()
If you're changing the syntax from
alex = CreateRobot()
to
new_robot_named('Alex')
I don't see what you gain from using exec...
py class robot(object):
...def __init__(self,name):
...   self.name = name
...def sayhi(self):
...   print Hi!  I'm %s! % self.name
...
py def new_robot_named(name, indict=globals()):
... indict[name] = robot(name)
...
py new_robot_named('Bert')
py new_robot_named('Ernie')
py Ernie.sayhi()
Hi!  I'm Ernie!
py Bert.sayhi()
Hi!  I'm Bert!
py import new
py temp = new.module('temp')
py new_robot_named('Alex', temp.__dict__)
py temp.Alex.sayhi()
Hi!  I'm Alex!
That said, I do think a 'new_robot_named' function is probably a better 
approach than trying to change the meaning of Python's assignment 
statement...

Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-23 Thread Georg Brandl
Michael Tobis wrote:
 I have a similar problem. Here's what I do:
 
 .def new_robot_named(name,indict=globals()):
 .   execstr = name +  = robot(' + name + ')
 .   exec(execstr,indict)
 
 .class robot(object):
 .   def __init__(self,name):
 .  self.name = name
 
 .   def sayhi(self):
 .  print Hi!  I'm %s! % self.name
 
 .if __name__==__main__:
 .   new_robot_named('Bert')
 .   new_robot_named('Ernie')
 .   Ernie.sayhi()
 .   Bert.sayhi()

Uh. Try explaining this to newbies... ;)

On a second thought, the idea is quite usable considering some differences:

class Robot(object):
# as above

class Robots(dict):
def new(self, name):
new_robot = Robot(name)
self[name] = new_robot
return new_robot
def __getattr__(self, name):
if name in self:
return self[name]
raise AttributeError

robots = Robots()
robots.new('Bert')
robots.new('Ernie')
robots.Bert.sayhi()
robots[Bert].sayhi()

for robot in robots:
robot.sayhi()

... etc ...

This doesn't include ugly globals() and exec tricks.

Georg
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-23 Thread Steven Bethard
Nick Coghlan wrote:
It also directly addresses the question of aliasing. Think about how 
Steven's modified dictionary would react to this code:

pete = CreateRobot(2, 3)
dad = pete
dad.move()
pete.move()
If you'd like to handle these cases, but you don't want to have to 
explain aliasing right off the bat, you could try something like:

py class Robot(object):
... def __init__(self):
... self.names = set()
... def move(self):
... if len(self.names) == 1:
... name, = self.names
... print robot with name %r moved % name
... else:
... print robot with names %r moved % sorted(self.names)
...
py class RobotDict(dict):
... def __setitem__(self, name, value):
... if isinstance(value, Robot):
... value.names.add(name)
... super(RobotDict, self).__setitem__(name, value)
...
py user_code = \
... nick = Robot()
... pete = Robot()
... dad = pete
... nick.move()
... dad.move()
... pete.move()
py exec user_code in RobotDict(Robot=Robot)
robot with name 'nick' moved
robot with names ['dad', 'pete'] moved
robot with names ['dad', 'pete'] moved
That is, you can just keep track of all the names of a Robot in the 
Robot object.  In the simple case, where there's only one name, you can 
display it as such.  In the more complicated case, where there's some 
aliasing, you can display the multiple aliases.  This means you don't 
have to teach about aliasing right off the bat, but if a student 
accidentally discovers it on their own, the machinery's there to explain 
it...

Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread Alex Martelli
André Roberge [EMAIL PROTECTED] wrote:

 alex = CreateRobot()
 anna = CreateRobot()
 
 alex.move()
 anna.move()

H -- while I've long since been identified as a 'bot, I can assure
you that my wife Anna isn't!


Alex
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread André

Jeremy Bowers wrote:
 On Fri, 21 Jan 2005 21:01:00 -0400, André Roberge wrote:
  etc. Since I want the user to learn Python's syntax, I don't want
to
  require him/her to write
  alex = CreateRobot(name = 'alex')
  to then be able to do
  alex.move()

 This is just my opinion, but I've been involved with teaching new
 programmers before so I think it is an informed one. I don't think
you
 teach a language by hiding how the language works, no matter what the
 intentions.

 You should be *minimizing* the magic. You're going to train your
students
 that Python objects have names (they don't) and that's going to mess
them
 up later. Actually, it's going to mess them up almost right away,
because
 how can they have a list of robots like this:

 for robot in robots:
   robot.turn_left()

They will not be able to do that.


 That can't work, right, the command inside the loop can only affect
the
 robot named robot, right?

 You can't teach Python if what you're actually teaching them is a
variant
 that you have created that is used nowhere else on Earth, and is
 internally inconsistent to boot (see loop above, the *real* Python
 variable semantics conflict with the semantics you are teaching).


I think you misunderstood my intentions, possibly because I explain
things too superficially.

 Considering that not a month goes by where someone doesn't post a
question
 related to this, and it has been a FAQ entry for as long as I've used
 Python, I think you are doing a major disservice to your users by
 training them that objects magically gets the name when assigned. I
 strongly urge you to do absolutely no pre-processing of any kind to
the
 programs they generate. (By which I mean changes to the code; running
 pychecker on it would be OK; and I'd urge you to resist the
temptation to
 process its output, either. Provide a translation table if you need
to,
 but they need to learn to read the real output, too.)

 Programming is hard enough with burdening people with pleasant
 falsehoods. Trust your students to handle the truth (and of course
 rationally minimize the truth they have to handle, and by using
Python
 you're off to a great start there). If they can't handle the truth,
with
 time, effort, and support, they *sure* as hell can't handle lies!

The environment in which students (my kids first, others later :-) will
learn is based on Richard Pattis's  Karel the Robot   (adapted for
Python in Guido van Robot).  They are presented with a robot that can
do four basic actions, as I described in a previous post.  It's been
used successfully in many places.

The students learn first the procedural aspect of python. Here's a
quick example of a program that they can write:

.def move_and_turn():
.move()
.turn_left()
.
.def draw_square():
.for i in range(4):
.move_and_turn()
.
.draw_square()
==
At this point, they don't know anything about objects and methods; but
they will have learned about functions and variables.  This is where
'Guido van Robot (GvR)', which has been used succesfully to teach
programming using a syntax somewhat similar to python, but not quite,
stops.  (Actually, you can't use variables in GvR).

I want to move beyond that and introduce objects and classes.

So, students will be able to write:
pete = CreateRobot(2, 3)
pete.move()

learning about objects and methods.

As for things like
for robot in robots:
do stuff

that will be for my use only: drawing robots on the screen, updating
the 'world' when robots pick stuff up, etc.  My intention is that the
students will use the EXACT python syntax, so that they don't know that
*I* have given a *name* to their robot(s) behind the scene.
I have to cut this short; I hope it clarifies my intentions.

André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread Scott David Daniels
Andr Roberge wrote:
Craig Ringer wrote:
On Fri, 2005-01-21 at 16:13 -0800, Andr wrote:
Short version of what I am looking for:
Given a class public_class which is instantiated a few times e.g.
a = public_class()
b = public_class()
c = public_class()
I would like to find out the name of the instances so that I could
create a list of them e.g.
['a', 'b', 'c']
...
Behind the scene, I have something like:
robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
and have mapped move() to correspond to robot_dict['robot'].move()
(which does lots of stuff behind the scene.)
...[good explanation]...
 Does this clarify what I am trying to do and why?
Yup.  Would something like this help?
parts = globals().copy()
parts.update(locals())
names = [name for name, value in parts.iteritems()
 if isinstance(value, Robot)] # actual class name here
Note, however, that
a = b = CreateRobot()
will give two different names to the same robot.
And even:
Karl = CreateRobot()
Freidrich = CreateRobot()
for robot in (Karl, Freidrich):
robot.move()
Will have two names for Freidrich -- Freidrich and robot
--Scott David Daniels
[EMAIL PROTECTED]
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread André

Steven Bethard wrote:
 If you have access to the user module's text, something like this
might
 be a nicer solution:

 py class Robot(object):
 ... def __init__(self):
 ... self.name = None
 ... def move(self):
 ... print robot %r moved % self.name
 ...
 py class RobotDict(dict):
 ... def __setitem__(self, name, value):
 ... if isinstance(value, Robot):
 ... value.name = name
 ... super(RobotDict, self).__setitem__(name, value)
 ...
 py user_code = \
 ... alex = Robot()
 ... anna = Robot()
 ... alex.move()
 ... anna.move()
 py robot_dict = RobotDict()
 py robot_dict['Robot'] = Robot
 py exec user_code in robot_dict
 robot 'alex' moved
 robot 'anna' moved

 Note that I provide a specialized dict in which to exec the user code
--
 this allows me to override __setitem__ to add the appropriate
attribute
 to the Robot as necessary.


I have tried this exact example (using Python 2.3 if it makes any
difference) and what I got was:
robot None moved
robot None moved

I checked what I wrote, used cut  paste on your code, removing the
leading junk, tried it again ... to no avail. :-(

André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread Nick Coghlan
André wrote:
I have tried this exact example (using Python 2.3 if it makes any
difference) and what I got was:
robot None moved
robot None moved
I checked what I wrote, used cut  paste on your code, removing the
leading junk, tried it again ... to no avail. :-(
Worked exactly as written for me, but I believe there were Python 2.4 changes 
relating to using exec with non-standard dictionaries.

Regards,
Nick.
--
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
http://boredomandlaziness.skystorm.net
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-22 Thread Nick Coghlan
André wrote:
So, students will be able to write:
pete = CreateRobot(2, 3)
pete.move()
learning about objects and methods.
As for things like
for robot in robots:
do stuff
that will be for my use only: drawing robots on the screen, updating
the 'world' when robots pick stuff up, etc.  My intention is that the
students will use the EXACT python syntax, so that they don't know that
*I* have given a *name* to their robot(s) behind the scene.
I have to cut this short; I hope it clarifies my intentions.
My (and, if I understand him correctly, Jeremy's) concern would be that error 
messages like Robot 'pete' has hit a wall! would give students the impression 
that the robots automatically know their name as a result of the assignment. In 
standard Python, that simply isn't true.

If, instead, CreateRobot looked something like:
def CreateRobot(street, avenue, name=None):
  if name is None:
name = Robot + Robot.getNextNumber()
  return Robot(street, avenue, name)
Then, using a simple assignment:
pete = CreateRobot(2, 3)
pete.move()
Would give an error like:
Robot1 has hit a wall
This could then be used to point out that objects named using assignment don't 
know about the names they have been given, and need to be told:

pete = CreateRobot(2, 3, Pete)
pete.move()
Pete has hit a wall
Instead of misleading the students (objects know what names they have been 
given), you have taught them a powerful truth - objects and the names you give 
them via assignment are entirely independent.

It also directly addresses the question of aliasing. Think about how Steven's 
modified dictionary would react to this code:

pete = CreateRobot(2, 3)
dad = pete
dad.move()
pete.move()
Internally, idioms like for robot in robots should be entirely unaffected - 
the registration of the robot instance with the global list of robots can be 
handled by the robot initialisation method.

Regards,
Nick.
--
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
http://boredomandlaziness.skystorm.net
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Craig Ringer
On Fri, 2005-01-21 at 16:13 -0800, Andr wrote:
 Short version of what I am looking for:
 
 Given a class public_class which is instantiated a few times e.g.
 
 a = public_class()
 b = public_class()
 c = public_class()
 
 I would like to find out the name of the instances so that I could
 create a list of them e.g.
 ['a', 'b', 'c']
 
 I've read the Python Cookbook, Python in a Nutshell, Programming
 Python, Learning Python, ... googled (probably missed something
 obvious), all to no avail.

Yep. The short answer is that the instances don't have names - they're
just bound to names in a particular scope. They can be bound to
different names in the same scope or in other scopes.

You can get a dictionary for a particular scope using locals() then
search it to find the key for a given value. That key will be the name
the object is bound to in that scope.

In general, you won't want to do that - the need to do so probably
suggests a design issue in what you're trying to do.

 If I can do the above, I believe I could do the following thing which
 is what I am really after eventually.
 
 Given the statement
 
  a = public_class()
 
 I would like to generate
 
  my_dict['a'] = private_class()
 
 so that one could write
 
  a.apparently_simple_method()
 
 and that, behind the scene, I could translate that as
 
  my_dict['a'].not_so_simple_method()

I'm not clear as to why you can't do this as part of the class of which
'a' is an instance.

 as well as do things like
 
  for name in my_dict:
  do_stuff(name)
 
 Any help, pointers, sketches or outline of solution would be greatly
 appreciated.

I'm not really able to grasp what you're trying to do (but others
might). It wouldn't hurt if you could post a description of what you're
actually trying to achieve - /why/ you want this - as that can often be
very helpful both in understanding what you're thinking and in
suggesting a suitable approach or alternative.

--
Craig Ringer

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Steven Bethard
André wrote:
Given the statement
a = public_class()
I would like to generate
my_dict['a'] = private_class()
so that one could write
a.apparently_simple_method()
and that, behind the scene, I could translate that as
my_dict['a'].not_so_simple_method()
as well as do things like
for name in my_dict:
   do_stuff(name)
Why can't you just make public_class a factory, alias the method in 
PrivateClass and access the names through locals()?

py class PrivateClass(object):
... def not_so_simple_method(self):
... print not so simple
... apparently_simple_method = not_so_simple_method
...
py def public_class():
... return PrivateClass()
...
py a = public_class()
py a.apparently_simple_method()
not so simple
py # add 'name' and 'value' to locals() before iteration starts
py name, value = None, None
py for name, value in locals().iteritems():
... if isinstance(value, PrivateClass):
... print name, value
...
a __main__.PrivateClass object at 0x01146D50
Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Andr Roberge
Craig Ringer wrote:
On Fri, 2005-01-21 at 16:13 -0800, Andr wrote:
Short version of what I am looking for:
Given a class public_class which is instantiated a few times e.g.
a = public_class()
b = public_class()
c = public_class()
I would like to find out the name of the instances so that I could
create a list of them e.g.
['a', 'b', 'c']
[snip]

I'm not really able to grasp what you're trying to do (but others
might). It wouldn't hurt if you could post a description of what you're
actually trying to achieve - /why/ you want this - as that can often be
very helpful both in understanding what you're thinking and in
suggesting a suitable approach or alternative.
Ok, here it goes... I am designing a learning environment for Python.
(See rur-ple.sourceforge.org for details of a *very early, still buggy* 
relase).  I have a world in which a
robot can accomplish four built-in instructions: move(), turn_left(), 
pick_beeper(), put_beeper().
turn_left() corresponds to a 90 degree left turn.  One can define a 
function to simulate a 90 degree right turn as follows:

def turn_right():
turn_left()
turn_left()
turn_left()
and call it as a built-in instruction thereafter.
By giving more and more complicated tasks for the robot to accomplish,
one can learn various programming concepts using python syntax:
def (as above), while, if, else, elif, ..
I have all of that working well so far (not on sourceforge yet).
Next, I want to introduce
the concept of classes and objects, again using python's syntax.
Behind the scene, I have something like:
robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
and have mapped move() to correspond to
robot_dict['robot'].move()
(which does lots of stuff behind the scene.)
I have tested robot_dict[] with more than one robot (each with
its own unique name)  and am now at the point where I would like
to have the ability to interpret something like:
alex = CreateRobot()
anna = CreateRobot()
alex.move()
anna.move()
etc. Since I want the user to learn Python's syntax, I don't
want to require him/her to write
alex = CreateRobot(name = 'alex')
to then be able to do
alex.move()
I have tried various things at the interpreter, found that
to a class 'a', I could see the instance 'b' created in
locals():
'a': class '__main__.a', 'b': __main__.a object at 0x011515D0
which tells me that there must be a way to catch b's name as it is
created, and do what I want to do.
Does this clarify what I am trying to do and why?
Andr
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread André
Using the method suggested by Steven Bethard, I *almost* got it working
the way I would like.
Here's my program:
===
.class PrivateClass(object):
.dict = {}
.def not_so_simple_method(self):
.for name in PrivateClass.dict.keys():
.if PrivateClass.dict[name] == self:
.print instance  + name +  called not so simple
.apparently_simple_method = not_so_simple_method

.def __init__(self):
.print instance created
.for name, value in globals().iteritems():
.if isinstance(value, PrivateClass):
.PrivateClass.dict[name] = value

.def public_class():
.return PrivateClass()

.print === start===
.alpha = public_class()
.print created alpha
.print PrivateClass.dict
.print ### alpha is not there\n

.beta = public_class()
.print created beta
.print PrivateClass.dict
.print ### we are always one behind in the dict content\n

.alpha.apparently_simple_method()
.beta.apparently_simple_method()
=
The output follows:
=== start===
instance created
created alpha
{}
### alpha is not there

instance created
created beta
{'alpha': __main__.PrivateClass object at 0x0117CDD0}
### we are always one behind in the dict content

instance alpha called not so simple
===
Note that instance beta was never recognized when it called apparently
simple method.

I'm sure there must be a way to do this

André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Steven Bethard
André wrote:
Using the method suggested by Steven Bethard, I *almost* got it working
the way I would like.
Here's my program:
===
.class PrivateClass(object):
.dict = {}
.def not_so_simple_method(self):
.for name in PrivateClass.dict.keys():
.if PrivateClass.dict[name] == self:
.print instance  + name +  called not so simple
.apparently_simple_method = not_so_simple_method
.def __init__(self):
.print instance created
.for name, value in globals().iteritems():
.if isinstance(value, PrivateClass):
.PrivateClass.dict[name] = value
.def public_class():
.return PrivateClass()
.print === start===
.alpha = public_class()
.print created alpha
.print PrivateClass.dict
.print ### alpha is not there\n
.beta = public_class()
.print created beta
.print PrivateClass.dict
.print ### we are always one behind in the dict content\n
.alpha.apparently_simple_method()
.beta.apparently_simple_method()
It looks like you want PrivateClass.dict updated every time that 
globals() is updated.  You can just use globals directly instead:

py class PrivateClass(object):
... def __init__(self, globals):
... self.globals = globals
... def apparently_simple_method(self):
... for name, value in self.globals.iteritems():
... if value is self:
... print instance %s called not so simple % name
...
py def public_class():
... return PrivateClass(globals())
...
py alpha = public_class()
py alpha.apparently_simple_method()
instance alpha called not so simple
py beta = public_class()
py beta.apparently_simple_method()
instance beta called not so simple
On the other hand, the iteration in 
PrivateClass.apparently_simple_method has a very bad code smell...

Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread André

Steven Bethard wrote:
 André wrote:
  Using the method suggested by Steven Bethard, I *almost* got it
working
  the way I would like.
[snip]

 It looks like you want PrivateClass.dict updated every time that
 globals() is updated.

yes, that is what I would like to do.

You can just use globals directly instead:

 py class PrivateClass(object):
 ... def __init__(self, globals):
 ... self.globals = globals
 ... def apparently_simple_method(self):
 ... for name, value in self.globals.iteritems():
 ... if value is self:
 ... print instance %s called not so simple % name
 ...
 py def public_class():
 ... return PrivateClass(globals())
 ...
 py alpha = public_class()
 py alpha.apparently_simple_method()
 instance alpha called not so simple
 py beta = public_class()
 py beta.apparently_simple_method()
 instance beta called not so simple

That's exactly what I was looking for; thank you!

 On the other hand, the iteration in
 PrivateClass.apparently_simple_method has a very bad code smell...

I'm not sure what you mean...
Is it because it makes use of information that is
exterior to the class, which is not passed as a parameter
to the method?
[feel free to ignore this question if you want; you have
already helped me tremendously!!!]

André

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Steven Bethard
Andr Roberge wrote:
Behind the scene, I have something like:
robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
and have mapped move() to correspond to
robot_dict['robot'].move()
(which does lots of stuff behind the scene.)
I have tested robot_dict[] with more than one robot (each with
its own unique name)  and am now at the point where I would like
to have the ability to interpret something like:
alex = CreateRobot()
anna = CreateRobot()
alex.move()
anna.move()
etc. Since I want the user to learn Python's syntax, I don't
want to require him/her to write
alex = CreateRobot(name = 'alex')
to then be able to do
alex.move()
How do you get the commands from the user?  Maybe you can preprocess the 
user code?

py class Robot(object):
... def __init__(self, name):
... self.name = name
... def move(self):
... print robot %r moved % self.name
...
py user_code = \
... alex = Robot()
... anna = Robot()
... alex.move()
... anna.move()
py new_user_code =  re.sub(r'(\w+)\s+=\s+Robot\(\)',
... r'\1 = Robot(name=\1)',
... user_code)
py print new_user_code
alex = Robot(name=alex)
anna = Robot(name=anna)
alex.move()
anna.move()
py exec new_user_code
robot 'alex' moved
robot 'anna' moved
Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Steven Bethard
André wrote:
Steven Bethard wrote:
André wrote:
Using the method suggested by Steven Bethard, I *almost* got it
working
the way I would like.
[snip]
It looks like you want PrivateClass.dict updated every time that
globals() is updated.

yes, that is what I would like to do.

You can just use globals directly instead:
py class PrivateClass(object):
... def __init__(self, globals):
... self.globals = globals
... def apparently_simple_method(self):
... for name, value in self.globals.iteritems():
... if value is self:
... print instance %s called not so simple % name
...
py def public_class():
... return PrivateClass(globals())
...
py alpha = public_class()
py alpha.apparently_simple_method()
instance alpha called not so simple
py beta = public_class()
py beta.apparently_simple_method()
instance beta called not so simple
That's exactly what I was looking for; thank you!

On the other hand, the iteration in
PrivateClass.apparently_simple_method has a very bad code smell...
I'm not sure what you mean...
Is it because it makes use of information that is
exterior to the class, which is not passed as a parameter
to the method?
[feel free to ignore this question if you want; you have
already helped me tremendously!!!]
There's a couple things I don't like about it:
(1) Generally, I don't like passing globals() around.  It's probably 
okay in this scenario though because if you want to have the user code 
in a different module, you can do something like:
def public_class():
return PrivateClass(usermodule.__dict__)

(2) The really bad code smell however is having to iterate through all 
the values in globals to find the key you're looking for...  Especially 
when you have to check the type of each item...  In a perfect world, you 
would already have a PrivateClass-name mapping somewhere and this 
should be a simple dict lookup instead of an iterative search...  See my 
other post about potentially pre-processing your user input to see how 
you can convert the iteration to a simple attribute lookup.

Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread André

Steven Bethard wrote:
 André Roberge wrote:
  Behind the scene, I have something like:
  robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
  and have mapped move() to correspond to
  robot_dict['robot'].move()
  (which does lots of stuff behind the scene.)
 
  I have tested robot_dict[] with more than one robot (each with
  its own unique name)  and am now at the point where I would like
  to have the ability to interpret something like:
 
  alex = CreateRobot()
  anna = CreateRobot()
 
  alex.move()
  anna.move()
 
  etc. Since I want the user to learn Python's syntax, I don't
  want to require him/her to write
  alex = CreateRobot(name = 'alex')
  to then be able to do
  alex.move()

 How do you get the commands from the user?  Maybe you can preprocess
the
 user code?

 py class Robot(object):
 ... def __init__(self, name):
 ... self.name = name
 ... def move(self):
 ... print robot %r moved % self.name
 ...
 py user_code = \
 ... alex = Robot()
 ... anna = Robot()
 ... alex.move()
 ... anna.move()
 py new_user_code =  re.sub(r'(\w+)\s+=\s+Robot\(\)',
 ... r'\1 = Robot(name=\1)',
 ... user_code)
 py print new_user_code
 alex = Robot(name=alex)
 anna = Robot(name=anna)
 alex.move()
 anna.move()
 py exec new_user_code
 robot 'alex' moved
 robot 'anna' moved


Smack!  (sound of hand slapping forehead).
Of course!  This is *much* better.
(In all honesty, I have trouble reading regular expression
notation but I can decode it enough to understand that I can
do this - and I already asked a question today on the list
about regular expressions, so I have not excuse for not having
thought of an approach like this.)

I will be already 'processing' the code to make sure that
statements/words like: import, exec, eval, input, raw_input, vars,
chr,   are not allowed in the user-defined instructions.
This will be just a simple addition.

Once again, thank you!  Both for this, and for the other example which
taught me something about the use of locals(), globals(), and functions
that return classes.There are so many corners of Python to explore
:-)

 Steve

--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Steven Bethard
Andr Roberge wrote:
Behind the scene, I have something like:
robot_dict = { 'robot' = CreateRobot( ..., name = 'robot') }
and have mapped move() to correspond to
robot_dict['robot'].move()
(which does lots of stuff behind the scene.)
I have tested robot_dict[] with more than one robot (each with
its own unique name)  and am now at the point where I would like
to have the ability to interpret something like:
alex = CreateRobot()
anna = CreateRobot()
alex.move()
anna.move()
etc. Since I want the user to learn Python's syntax, I don't
want to require him/her to write
alex = CreateRobot(name = 'alex')
to then be able to do
alex.move()
If you have access to the user module's text, something like this might 
be a nicer solution:

py class Robot(object):
... def __init__(self):
... self.name = None
... def move(self):
... print robot %r moved % self.name
...
py class RobotDict(dict):
... def __setitem__(self, name, value):
... if isinstance(value, Robot):
... value.name = name
... super(RobotDict, self).__setitem__(name, value)
...
py user_code = \
... alex = Robot()
... anna = Robot()
... alex.move()
... anna.move()
py robot_dict = RobotDict()
py robot_dict['Robot'] = Robot
py exec user_code in robot_dict
robot 'alex' moved
robot 'anna' moved
Note that I provide a specialized dict in which to exec the user code -- 
this allows me to override __setitem__ to add the appropriate attribute 
to the Robot as necessary.

Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: finding name of instances created

2005-01-21 Thread Jeremy Bowers
On Fri, 21 Jan 2005 21:01:00 -0400, Andr Roberge wrote:
 etc. Since I want the user to learn Python's syntax, I don't want to
 require him/her to write
 alex = CreateRobot(name = 'alex')
 to then be able to do
 alex.move()

This is just my opinion, but I've been involved with teaching new
programmers before so I think it is an informed one. I don't think you
teach a language by hiding how the language works, no matter what the
intentions.

You should be *minimizing* the magic. You're going to train your students
that Python objects have names (they don't) and that's going to mess them
up later. Actually, it's going to mess them up almost right away, because
how can they have a list of robots like this:

for robot in robots:
robot.turn_left()

That can't work, right, the command inside the loop can only affect the
robot named robot, right? 

You can't teach Python if what you're actually teaching them is a variant
that you have created that is used nowhere else on Earth, and is
internally inconsistent to boot (see loop above, the *real* Python
variable semantics conflict with the semantics you are teaching). 

Considering that not a month goes by where someone doesn't post a question
related to this, and it has been a FAQ entry for as long as I've used
Python, I think you are doing a major disservice to your users by
training them that objects magically gets the name when assigned. I
strongly urge you to do absolutely no pre-processing of any kind to the
programs they generate. (By which I mean changes to the code; running
pychecker on it would be OK; and I'd urge you to resist the temptation to
process its output, either. Provide a translation table if you need to,
but they need to learn to read the real output, too.)

Programming is hard enough with burdening people with pleasant
falsehoods. Trust your students to handle the truth (and of course
rationally minimize the truth they have to handle, and by using Python
you're off to a great start there). If they can't handle the truth, with
time, effort, and support, they *sure* as hell can't handle lies!
-- 
http://mail.python.org/mailman/listinfo/python-list