Re: finding name of instances created
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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