On Fri, 31 Oct 2008, Peter Otten wrote: > John O'Hagan wrote: > > Here's a strange one for you: > > > > I have a generator function which produces lists of numbers and takes > > options which influence the output. The generator contains a loop, and to > > enable the options to have a different value on each iteration, the > > options may themselves be instances of the same generator, in the form of > > attributes of an optparse object. In the body of the loop, the next() > > method is called on each generator to get the new value each time. [..] > > > > The problem: whether it works or not depends on what name is given to the > > destination in parser.values()! Strange but true. [...] > > > > Here's the code: > > > > import sys > > from optparse import OptionParser > > > > def my_callback(option, opt_str, value, parser): > > > > rargs = parser.rargs > > > > if rargs[0] == "CTRL:" : > > setattr(parser.values, option.dest+"_ctrl", rargs[1].split()) > > else: > > value = abs(int(rargs[0])) > > setattr(parser.values, option.dest, value) > > > > def parse(option_list): > > > > parser = OptionParser() > > > > parser.add_option("--add", action="callback", callback=my_callback, > > dest="add") ## The troublesome name! > > > > (options, args) = parser.parse_args(option_list) > > return options > > > > > > def numerical_ctrl(generator): > > > > for number_list in generator: > > for number in number_list: > > yield number > > > > def dummy_ctrl(value): > > while 1: > > yield value > > > > #This next bit should ideally be incorporated into the callback function > > #above (later!) > > #It converts the attributes of the "options" object to generators. > > > > def iterizer( options ): > > > > for opt in vars( options ) : > > > > if "_ctrl" in opt: > > ctrl_opts_list = getattr( options, opt ) > > setattr(options, opt, dummy_ctrl( getattr( options, opt ) ) ) > > opt = opt.replace( "_ctrl", "" ) > > ctrl_opts = parse( ctrl_opts_list ) > > ctrl_opts = iterizer( ctrl_opts ) > > generator = phrase_engine( ctrl_opts ) > > generator = numerical_ctrl( generator ) > > else: > > generator = dummy_ctrl( getattr( options, opt ) ) > > > > setattr (options, opt , generator) > > > > return options > > > > #The number list generator: > > > > def phrase_engine(options): > > > > counter = 0 > > while counter < 10: > > > > sequence = [1, 2, 3] > > > > add = options.add.next() ##Here is the troublesome name again. > > > > if add : > > sequence = [ i + add for i in sequence ] > > > > yield sequence > > > > counter += 1 > > > > options = parse( sys.argv[ 1: ] ) > > options = iterizer(options) > > > > for i in phrase_engine(options): > > print i > > Just a quick note: Your iterizer() implementation seems to depend on xxx > > occuring before xxx_ctrl.
[...] Thanks for your eagle eye, Peter, that's exactly what it was; I hadn't realized the original xxx option was still in the game, a fact that was masked by that ugly "ctrl_" kludge. > > While you can enforce that with sorted(vars(options)) I suggest that you > try to simplify your code a bit -- you know, debugging being twice as hard > as coding... > [...] That's excellent advice, my callback function now simply stores the string after "CTRL:" as a word list (without creating a new destination), and iterizer() just checks if each option's value is a list: def iterizer(options): for opt in vars(options) : value = getattr(options, opt) if type(value) is list: ctrl_opts = parse(value) ctrl_opts = iterizer(ctrl_opts) generator = phrase_engine(ctrl_opts) generator = numerical_ctrl(generator) else: generator = dummy_ctrl(getattr(options, opt)) setattr (options, opt , generator) return options I have a feeling type-checking is a little bit naughty as well, but it's a foolproof way to tell which kind of option has been applied, and it works! Thanks again, John -- http://mail.python.org/mailman/listinfo/python-list