Hi, I wrote (on -users, but have moved the discussion here to -devel): > > I was wondering, though, whether there'd be any support for some work > > which tidied up the near-duplicate code in axes.py.
John Hunter replied: > Certainly, but probably not using meta-classes. > [...] > I'm disinclined to use python black magic -- I find it makes the code > harder to grok for the typical scientist, and these are our main > developers. Also, Darren Dale replied: > It's true. That bit of code looks like Perl to me. There's no need to be rude :-) The generalised docstrings are a bit ugly because they're unavoidably filled with phrases like "set the x-axis limits to go from xmin to xmax", which need to be changed to "set the y-axis limits to go from ymin to ymax" for the other function. The %(axis_letter)s stuff is quite verbose, unfortunately, but it's the same as in things like kwargs set the Text properties. Valid properties are %(Text)s This does make the docstring a bit harder to work with, but the alternative is to write it out twice, and then ensure the two near-copies are kept in sync as changes are made. Now of course this isn't impossible, but that kind of thing does add to the maintenance burden in my experience. Keeping the two copies of the code in sync requires effort, too, and it's easy to miss things; e.g., set_xlim() includes self._process_unit_info(xdata=(xmin, xmax)) but set_ylim() doesn't --- which is correct? panx() and zoomx() include xmin, xmax = self.viewLim.intervalx().get_bounds() but pany() and zoomy() have no analogous calls --- which is correct? The docstrings of set_xlabel() and set_ylabel() are formatted differently (obviously this is not a critical problem but still), and the examples in axhline() and axvline()'s docstrings are slightly different. There was the bug with hlines() and vlines() that lead to my query. I'm not trying to be annoying in pointing out these things, just saying that although there is a bit of a learning curve in the 'only write the function once' approach, I've found that it does save trouble in the long run. The metaclass itself is only really used to automate the process of creating the two specific functions from the one generic one. It could be left out, instead meaning that you'd write something like class Axes: [...] def set__AXISLETTER_scale(self, [...]): # [...] # do stuff # [...] set_xscale = make_specific_function(set__AXISLETTER_scale, X_TRAITS) set_yscale = make_specific_function(set__AXISLETTER_scale, Y_TRAITS) The make_specific_function() function is a little bit hairy and there might well be a better way to do it. My current implementation fiddles with the bytecode of the general function, and while I think it works correctly, this kind of malarkey can certainly lead to bugs which are very difficult to unravel if the "behind the scenes" stuff (i.e., make_specific_function() in this case) has problems. Without using something like make_specific_function(), you could do something more like John's suggestion: def set_xscale(self, value, basex = 10, subsx = None): """ [...] x docstring [...] """ self._set_scale(self.X_TRAITS, value, basex, subsx) def set_yscale(self, value, basey = 10, subsy = None): """ [...] y docstring [...] """ self._set_scale(self.Y_TRAITS, value, basey, subsy) def _set_scale(self, traits, value, base, subs): assert(value.lower() in ('log', 'linear', )) if value == 'log': traits.axis.set_major_locator(mticker.LogLocator(base)) traits.axis.set_major_formatter(mticker.LogFormatterMathtext(base)) traits.axis.set_minor_locator(mticker.LogLocator(base, subs)) traits.transfunc.set_type(mtrans.LOG10) min_val, max_val = traits.limfunc() if min(min_val, max_val) <= 0: self.autoscale_view() elif value == 'linear': traits.axis.set_major_locator(mticker.AutoLocator()) traits.axis.set_major_formatter(mticker.ScalarFormatter()) traits.axis.set_minor_locator(mticker.NullLocator()) traits.axis.set_minor_formatter(mticker.NullFormatter()) traits.transfunc.set_type(mtrans.IDENTITY) where the 'traits' stuff allows you to pass around the 'limfunc = self.get_xlim' etc. all in one go. 'X_TRAITS' and 'Y_TRAITS' would be set up in __init__(). Maybe 'X_METHODS' and 'Y_METHODS' would be better names. With the above approach, you do still end up with two near-copies of the docstring but at least the actual code is all in one place. Anyway. Just thought I'd make the suggestion. If there's interest I can tidy up what I've got and post it. Or a patch which takes the last-mentioned approach above. Ben. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel