Instances' __setitem__ methods
I was recently trying to implement a dict-like object which would do some fancy stuff when it was modified, and found that overriding the __setitem__ method of an instance did not act the way I expected. The help documentation (from help(dict.__setitem__)) claims that "d.__setitem__(k,v)" is equivalent to "d[k]=v", but I've produced this code that, on Python 2.6, acts differently in the two cases. def print_args( key, value ): print "print_args called: key = %s, value = %s" %(key,value) class MyDict( dict ): def __init__( self ): dict.__init__( self ) self.__setitem__ = print_args def __setitem__( self, key, value ): print "ModelDict.__setitem__ called" dict.__setitem__( self, key, value ) d = MyDict() print "d.__setitem__(0,1):", d.__setitem__(0,1) print "d[0]=1:", d[0]=1 I would expect the two setitems to both call print_args, but that's not what happens. In the first case, it calls print_args, but in the second case, the __setitem__ declared in MyDict is called instead. The documentation at http://docs.python.org/reference/datamodel.html#specialnames says that for new-style classes, "x[i]" is equivalent to "type(x).__getitem__(x, i)". I assume that "x[i]=y" has similarly been changed to be equivalent to "type(x).__setitem__(x, i, y)", since that would produce the results that I'm getting. Is the help documentation for dict.__setitem__ just outdated, or am I missing some subtlety here? Also: when I say "d.f(*args)", am I correct in thinking that d checks to see if it has an instance attribute called "f", and if it does, calls f(*args); and if it doesn't, checks whether its parent class (and then its grandparent, and so on) has a class attribute called "f", and if it does, calls f(x, *args)? -- http://mail.python.org/mailman/listinfo/python-list
Adding an interface to existing classes
I'm writing a geometry package, with Points and Lines and Circles and so on, and eventually I want to be able to draw these things on the screen. I have two options so far for how to accomplish this, but neither of them sits quite right with me, and I'd like the opinion of comp.lang.python's wizened elders. Option 1. Subclassing. The most Pythonic way would seem to be writing subclasses for the things I want to display, adding a ".draw(...)" method to each one, like this: class DrawablePoint( geometry.Point ): class draw( self, ... ): ... When the time comes to draw things, I'll have some list of objects I want drawn, and say for x in to_draw: x.draw(...) I see a problem with this, though. The intersection of two lines is (usually) an object of type Point. Since DrawableLine inherits from Line, this means that unless I redefine the "intersect" method in DrawableLine, the intersection of two DrawableLines will be a Point object, not a DrawablePoint. I don't want to saddle the user with the burden of converting every method output into its corresponding Drawable subclass, and I don't want to redefine every method to return an instance of said subclass. I see no other options if I continue down the subclassing path. Am I missing something? Option 2. A "draw" function, with a function dictionary. This feels weird, but is fairly simple to write, use, and extend. We have a module with a "draw_functions" dictionary that maps types onto functions, and a "draw" function that just looks up the proper type in the dictionary and calls the corresponding function. If you create your own object, you can just add a new entry to the dictionary. The implementation is simple enough to outline here: In file "geometry/gui.py": def draw_point(...): ... def draw_line(...): ... draw_functions = {geometry.Point: draw_point, geometry.Line: draw_line, ...} def draw( x, *args, **kwargs ): for type, callback in draw_functions.iteritems(): if isinstance(x, type): callback(x, *args, **kwargs) else: raise TypeError("don't know how to draw things of type " "{0}".format(type(x))) In the file that uses this: # Drawing a predefined type of object: geometry.gui.draw(some_point, ...) # Here we define a new kind of object and tell the package how to draw it. class MyObject(GeometricObject): ... def draw_my_object(...): ... geometry.gui.draw_functions[MyObject] = draw_my_object # And now we draw it. geometry.gui.draw(MyObject(...), ...) If I feel fancy, I might use a decorator for adding entries to draw_functions, but this is basically how it'd work. The second way feels kludgey to me, but I'm leaning towards it because it seems like so much less work and I'm out of ideas. Can anyone help, explaining either a different way to do it or why one of these isn't as bad as I think? Thanks for your time! -Spencer -- http://mail.python.org/mailman/listinfo/python-list
Re: Adding an interface to existing classes
On Dec 23, 9:13 am, Terry Reedy wrote: > On 12/22/2011 3:21 AM, Spencer Pearson wrote: > > > I'm writing a geometry package, with Points and Lines and Circles and > > so on, and eventually I want to be able to draw these things on the > > screen. I have two options so far for how to accomplish this, but > > neither of them sits quite right with me, and I'd like the opinion of > > comp.lang.python's wizened elders. > > > Option 1. Subclassing. > > The most Pythonic way would seem to be writing subclasses for the > > things I want to display, adding a ".draw(...)" method to each one, > > like this: > > Option 2. A "draw" function, with a function dictionary. > > Option 3? Add a draw method to existing classes, rather than subclassing? > > -- > Terry Jan Reedy Thanks for the response! Do you mean something like this? class Point(GeometricObject): def intersect(self, other): ... def union(self, other): ... def draw(self, ...): ... I'd like to avoid this, because... well, what I want is a geometry package, and it seems to me that whistles and bells like GUI support ought to be confined to subpackages. I'd look at this and think, "the rest of the Point class deals with fundamental geometric reality. What's this GUI method doing mixed in with my beautiful mathematical purity?" Is this the wrong attitude to take? Or did you mean this? In file "geometry/gui.py": def draw_point(point, ...): ... Point.draw = draw_point I've never modified an existing class before, and I fear the unfamiliar. If that's what you meant... it's really an acceptable thing to do? It seems like somebody might see "some_point.draw(...)" and be confused by the method's absence in the Point class definition. (A hybrid approach would be to say "draw = geometry.gui.draw_point" inside the body of the Point class, setting the attribute there instead of in gui.py, but that makes me uneasy for the same reason as putting the function's full definition in the class.) Thanks again, -Spencer -- http://mail.python.org/mailman/listinfo/python-list
Re: Adding an interface to existing classes
(I'm sorry for my delayed response -- I've been travelling and not had reliable Internet access.) >> Spencer, i would re-think this entire project from the >> beginning. You are trying to make an object out of everything. You >> don't need to make an object of EVERYTHING. > > Very true. I'm not sure I understand. Surely you're not both saying that I shouldn't write a Point class? Here's an expression I'd like very much to be able to type: sphere1.intersect(sphere2).rotated(angle, axis) If I represented points with something already defined, maybe a tuple or a numpy array, then that would risk that the spheres were tangent, that their intersection was not a Circle (a GeometricObject, with a .rotated method), but a point (a tuple, without one). On 2011-12-25, Steven D'Aprano wrote: > class Line: > intersection_kind = Point > def intersection(self, other): > blah() > return self.intersection_kind(a, b) > > class DrawableLine(Line): > intersection_kind = DrawablePoint If I objected that the intersection of two Lines might, once in a blue moon, be a Line (because they're the same line), this seems like it would edge towards the factory solution that Ian Kelly suggested (i.e. not "return self.intersection_kind(...)", but "return self.factory.create_point(...)" or something similar). Is that so? -Spencer -- http://mail.python.org/mailman/listinfo/python-list
Re: Adding an interface to existing classes
On Dec 25 2011, 2:58 pm, Terry Reedy wrote: > On 12/24/2011 6:49 PM,SpencerPearsonwrote: > > > On Dec 23, 9:13 am, Terry Reedy wrote: > >> On 12/22/2011 3:21 AM,SpencerPearsonwrote: > > >>> I'm writing a geometry package, with Points and Lines and Circles and > >>> so on, and eventually I want to be able to draw these things on the > >>> screen. I have two options so far for how to accomplish this, but > >>> neither of them sits quite right with me, and I'd like the opinion of > >>> comp.lang.python's wizened elders. > > >>> Option 1. Subclassing. > >>> The most Pythonic way would seem to be writing subclasses for the > >>> things I want to display, adding a ".draw(...)" method to each one, > >>> like this: > > There are people who would advocate a Drawable base class with a virtual > or abstract .draw method and that DrawablePoint, etc, inherit from > Drawable and Point. > > >>> Option 2. A "draw" function, with a function dictionary. > > >> Option 3? Add a draw method to existing classes, rather than subclassing? > > Thanks for the response! Do you mean something like this? > > class Point(GeometricObject): > > def intersect(self, other): > > ... > > I am interpreting this to mean that you have a world coordinate system > for instances that have location and size. > > > def union(self, other): > > ... > > def draw(self, ...): > > ... > > Yes. I would consider that Option 0, the default, unless you have good > reason to choose another. I would certainly include it on a list of options. > > > I'd like to avoid this, because... well, what I want is a geometry > > package, and it seems to me that whistles and bells like GUI support > > ought to be confined to subpackages. I'd look at this and think, "the > > rest of the Point class deals with fundamental geometric reality. > > What's this GUI method doing mixed in with my beautiful mathematical > > purity?" > > By default, all Python objects have a text representation method. I do > not see that giving all concrete geometric objects (with a location and > size) a visual representation is much different. I would use drawing > functions that accept the coordinates and distances of your geometry > world and translate to low-level pixel functions for a particular gui > system. I agree that your geometrical objects should not know about > pixels, screens, windows, and aspect ratios. > > > Is this the wrong attitude to take? > > It depends on *your* goal and values. > > > Or did you mean this? > > In file "geometry/gui.py": > > def draw_point(point, ...): > > ... > > Point.draw = draw_point > > > I've never modified an existing class before, and I fear the > > unfamiliar. If that's what you meant... it's really an acceptable > > thing to do? > > Yes, in my opinion. The advantage of this is putting all the draw > methods together, and possibly having more than one one set. On the > other hand, one needs to know the data attributes of each class to > understand its draw method. > > > It seems like somebody might see "some_point.draw(...)" > > and be confused by the method's absence in the Point class definition. > > With either suboption, you should put an abstract .draw method in the > GeometricObject base class. > > I would look at various game, graph, geometry, and gui packages handle > drawing for more ideas. > > -- > Terry Jan Reedy (I'm sorry for my delayed response -- I've been travelling and not had reliable Internet access.) On 2011-12-25, Terry Reedy wrote: > There are people who would advocate a Drawable base class with a virtual > or abstract .draw method and that DrawablePoint, etc, inherit from > Drawable and Point. Yes... yes, that makes sense to me. > By default, all Python objects have a text representation method. I do > not see that giving all concrete geometric objects (with a location and > size) a visual representation is much different. I would use drawing > functions that accept the coordinates and distances of your geometry > world and translate to low-level pixel functions for a particular gui > system. I agree that your geometrical objects should not know about > pixels, screens, windows, and aspect ratios. Ha! Oh, I've been being silly. I was going to claim that since there is no standard Python GUI, I ought not chain myself to any one of the candidates. Then I learned that Tkinter comes standard with Python. Oops. All right, now that I know that, the comparison to having a text representation seems very reasonable. I'll definitely reconsider making the draw() method a requirement for all GeometricObjects. >> I've never modified an existing class before, and I fear the >> unfamiliar. If that's what you meant... it's really an acceptable >> thing to do? > > Yes, in my opinion. The advantage of this is putting all the draw > methods together, and possibly having more than one one set. On the > other hand, one needs to know the data attributes of each class to > understand its draw me
Re: Adding an interface to existing classes
(I'm sorry for my delayed response -- I've been travelling and not had reliable Internet access.) On 2011-12-25, Ian Kelly wrote: > On Thu, Dec 22, 2011 at 1:21 AM, Spencer Pearson > wrote: >> I see a problem with this, though. The intersection of two lines is >> (usually) an object of type Point. Since DrawableLine inherits from >> Line, this means that unless I redefine the "intersect" method in >> DrawableLine, the intersection of two DrawableLines will be a Point >> object, not a DrawablePoint. I don't want to saddle the user with the >> burden of converting every method output into its corresponding >> Drawable subclass, and I don't want to redefine every method to return >> an instance of said subclass. I see no other options if I continue >> down the subclassing path. Am I missing something? > > You could solve this with a factory. Instead of having > Line.intersection() create a Point directly, have it call > self.factory.create_point(). In the drawing module, replace the > factory for the subclasses with one that creates drawable classes > instead. Oh, that's a neat idea. Yes, I think that does exactly what I want! Thanks very much! > This will also work, but inheritance complicates things a > little. ... > ... Probably the easiest way to do this correctly is to follow the > MRO that Python has conveniently already built for you. Something > like: > > def draw(x, *args, **kwargs ): > for class_ in type(x).__mro__: > if class_ in draw_functions: > draw_functions[class_](*args, **kwargs) > break > else: > raise TypeError("don't know how to draw things of type " > "{0}".format(type(x))) You're right, you're right. My implementation was sloppy. I think I'll go with your factory solution, but thanks for the fixed version of draw() -- I've never seen __mro__ before, and it seems to be just the tool for this job! -Spencer -- http://mail.python.org/mailman/listinfo/python-list
Tuples vs. variable-length argument lists
Hi! This might be more of a personal-preference question than anything, but here goes: when is it appropriate for a function to take a list or tuple as input, and when should it allow a varying number of arguments? It seems as though the two are always interchangeable. For a simple example... def subtract( x, nums ): return x - sum( nums ) ... works equally well if you define it as "subtract( x, *nums )" and put an asterisk in front of any lists/tuples you pass it. I can't think of any situation where you couldn't convert from one form to the other with just a star or a pair of parentheses. Is there a generally accepted convention for which method to use? Is there ever actually a big difference between the two that I'm not seeing? -- http://mail.python.org/mailman/listinfo/python-list
Class changes in circular imports when __name__ == '__main__'
Hi! I'm writing a package with several files in it, and I've found that "isinstance" doesn't work the way I expect under certain circumstances. Short example: here are two files. # fileone.py import filetwo class AClass( object ): pass if __name__ == '__main__': a = AClass() filetwo.is_aclass( a ) # filetwo.py import fileone def is_aclass( a ): print "The argument is", ("" if isinstance(a, fileone.AClass) else "not"), "an instance of fileone.AClass" If you run fileone.py, it will tell you that "The argument is not an instance of fileone.AClass", which seems strange to me, given that the fileone module is the one that CREATES the object with its own AClass class. And if you replace "if __name__ == '__main__'" with "def main()", start Python, import fileone, and call fileone.main(), it tells you that the argument IS an instance of AClass. So, the module's name change to __main__ when you run it on its own... well, it looks like it puts all of the things defined in fileone in the __main__ namespace INSTEAD of in the fileone module's namespace, and then when filetwo imports fileone, the class is created again, this time as fileone.AClass, and though it's identical in function to __main__.AClass, one "is not" the other. Is this kind of doubled-back 'isinstance' inherently sinful? I mean, I could solve this problem by giving all of my classes "classname" attributes or something, but maybe it's just a sign that I shouldn't have to do this in the first place. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class changes in circular imports when __name__ == '__main__'
All right, thank you for helping! I'd had a little voice in the back of my mind nagging me that it might not be logical to include a bunch of classes and function definitions in my startup file, but I never got around to splitting it up. The module/script distinction makes sense, and it seems more elegant, too. Also, my program works now that I've rearranged things, which is a plus. Thanks! -- http://mail.python.org/mailman/listinfo/python-list