On Fri, 11 Jan 2008 08:29:18 -0800, dg.google.groups wrote: > Hi all, > > I'm part of a small team writing a Python package for a scientific > computing project. The idea is to make it easy to use for relatively > inexperienced programmers. As part of that aim, we're using what we're > calling 'magic functions', and I'm a little bit concerned that they are > dangerous code. I'm looking for advice on what the risks are (e.g. > possibility of introducing subtle bugs, code won't be compatible with > future versions of Python, etc.). > > Quick background: Part of the way our package works is that you create a > lot of objects, and then you create a new object which collects together > these objects and operates on them. We originally were writing things > like: > > obj1 = Obj(params1) > obj2 = Obj(params2) > ... > bigobj = Bigobj(objects=[obj1,obj2]) > bigobj.run() > > This is fine, but we decided that for clarity of these programs, and to > make it easier for inexperienced programmers, we would like to be able > to write something like: > > obj1 = Obj(params1) > obj2 = Obj(params2) > ... > run() > > The idea is that the run() function inspects the stack, and looks for > object which are instances of class Obj, creates a Bigobj with those > objects and calls its run() method. > > So, any comments on that approach?
1. Even if you implement magic functions, don't get rid of the straightforward "hard way". Magic functions should be for convenience only. The user should be free to choose to do it the straightforward, explicit "hard way", and not rely on the magic. In your example, Bigobj should still be available to users, and should be documented at least as well as the magic run() function. The main reason for this (aside from the philosophical question) is that users often have different needs that you can anticipate, and your magic might not meet those unanticipated needs, forcing the user to resort to hacks and workarounds. 2. If your intention is to perform this operation on all Objs, then it might be a good idea to arrange your code so that Objs are already registered by the time the user gets them. One way to do this has already been mentioned: by having the Obj class track all its instances. Another way that might be preferable is to have Bigobj create Objs on behalf of the user. Here's a stripped down example: class Bigobj(object): def __init__(self): self.tracked_objs = set() def create_object(self,*args): obj = Obj(*args) self.tracked_objs.add(obj) return obj def run(self): for obj in self.tracked_objs: # do something with obj bigobj = Bigobj() obj1 = bigobj.create_object(params1) obj2 = bigobj.create_object(params2) # maybe do something with obj1 and obj2 here bigobj.run() Carl Banks -- http://mail.python.org/mailman/listinfo/python-list