Is this optparse object abuse?

J

John O'Hagan

Hello,

I've recently found it convenient to do something like this:

options = optparse_function(sys.argv[1:])

##print options =>
##{option_one:4, option_two:[5, 3, 7, 8, 6], option_three:'/home/files'}

#(Note that this is not a dictionary, even though it looks like one; it's how
#an optparse instance reports what it's holding.)

def function_one(options):
foo = options.option_one
do stuff with foo

def function_two(options):
foo = options.option_one
bar = options.option_two
options.old_option_two = bar
bar = bar * foo
options.option_two = bar

def function_three(options):
blop = options.old_option_two
blip = options.option_three
do stuff with blip and blop
....

In other words, using the optparse object to hold as attributes everything
needed by all the functions and methods in the module, and simply passing it
holus bolus to all them and just pulling out what's actually needed inside
the function, even adding new attributes or reassigning old ones along the
way.

I find it convenient (esp. when there are a lot of options spread over a lot
of functions) because I don't need to fuss about with positional arguments,
keyword dictionaries, default values etc., and it's also easy to pass new or
altered stuff from one function or method to another without polluting the
namespace, as you only get the names out of the object when you assign a name
to the attribute inside a function or method, and vice-versa. And adding
a "feature" to a function is as easy as typing "options.blah".

And if this works, why not use a generic object for the same purpose when
options are not involved?

However, before I get too excited: it does seem too easy, and I have no idea
how these objects are implemented - for all I know I'm using a truck to
deliver a ping-pong ball.

My question is: is this horribly inefficient or otherwise wrong?

Thanks,

John O'Hagan
 
D

Diez B. Roggisch

In other words, using the optparse object to hold as attributes everything
needed by all the functions and methods in the module, and simply passing
it holus bolus to all them and just pulling out what's actually needed
inside the function, even adding new attributes or reassigning old ones
along the way.

I find it convenient (esp. when there are a lot of options spread over a
lot of functions) because I don't need to fuss about with positional
arguments, keyword dictionaries, default values etc., and it's also easy
to pass new or altered stuff from one function or method to another
without polluting the namespace, as you only get the names out of the
object when you assign a name to the attribute inside a function or
method, and vice-versa. And adding a "feature" to a function is as easy as
typing "options.blah".

And if this works, why not use a generic object for the same purpose when
options are not involved?

However, before I get too excited: it does seem too easy, and I have no
idea how these objects are implemented - for all I know I'm using a truck
to deliver a ping-pong ball.

My question is: is this horribly inefficient or otherwise wrong?

Partially, I do the same - passing around the opts-object so that I don't
have to e.g. pass verbosity-levels around explicit.

*BUT* what I would *never* do is to assign to the options-object! If you
need state that changes and is something else that configuration, use a
class and instance-attributes together with self to communicate and alter
that state. The reason is simply that you don't do it much differently now,
but the options-object gets a god-like status it shouldn't have. Without
tracing all calls in the correct order, it is impossible to say what state
the object might have.



Diez
 
J

John O'Hagan

In other words, using the optparse object to hold as attributes
everything needed by all the functions and methods in the module, and
simply passing it holus bolus to all them and just pulling out what's
actually needed inside the function, even adding new attributes or
reassigning old ones along the way.
[...]

My question is: is this horribly inefficient or otherwise wrong?

Partially, I do the same - passing around the opts-object so that I don't
have to e.g. pass verbosity-levels around explicit.

*BUT* what I would *never* do is to assign to the options-object! If you
need state that changes and is something else that configuration, use a
class and instance-attributes together with self to communicate and alter
that state. The reason is simply that you don't do it much differently now,
but the options-object gets a god-like status it shouldn't have. Without
tracing all calls in the correct order, it is impossible to say what state
the object might have.

I see your point but I want to be clear on the correct approach: to take my
original example, is the following better:

class State:
pass
state = State()
....
def function_two(options, state):

bar = options.option_two
state.old_option_two = bar
bar = bar * foo
state.new_option_two = bar

def function_three(options, state):
blop = state.old_option_two
....
?

But don't we have the same problem with keeping track of state? And where
does "self" come into it (apart from its role in defining a class) if we are
just using the class as a container?

Apologies for my obtuseness,

Regards,

John
 
D

Diez B. Roggisch

John said:
In other words, using the optparse object to hold as attributes
everything needed by all the functions and methods in the module, and
simply passing it holus bolus to all them and just pulling out what's
actually needed inside the function, even adding new attributes or
reassigning old ones along the way.
[...]

My question is: is this horribly inefficient or otherwise wrong?

Partially, I do the same - passing around the opts-object so that I don't
have to e.g. pass verbosity-levels around explicit.

*BUT* what I would *never* do is to assign to the options-object! If you
need state that changes and is something else that configuration, use a
class and instance-attributes together with self to communicate and alter
that state. The reason is simply that you don't do it much differently
now, but the options-object gets a god-like status it shouldn't have.
Without tracing all calls in the correct order, it is impossible to say
what state the object might have.

I see your point but I want to be clear on the correct approach: to take
my original example, is the following better:

class State:
pass
state = State()
...
def function_two(options, state):

bar = options.option_two
state.old_option_two = bar
bar = bar * foo
state.new_option_two = bar

def function_three(options, state):
blop = state.old_option_two
...
?

But don't we have the same problem with keeping track of state? And where
does "self" come into it (apart from its role in defining a class) if we
are just using the class as a container?

Make function_one and function_two methods of class "State" (you'd obviously
like to rename it something more useful then)

Options are something that is given by the user. They should be considered
read-only. Any state that drives your logic should be explicit, and if
several functions rely on shared state, then a class is the usual answer.
Alternatively, you can of course pass explicit arguments.

Passing opaque state objects though is usually not the way to go. There are
a few circumstances where this is justified - for example in very loosely
coupled scenarios where state is passed through layers of otherwise
agnostic code that you don't want to adapt just because some deep-down
piece of code needs a new parameter.

But these occasions really are very rare IMHO.

Diez
 
B

Bruno Desthuilliers

John O'Hagan a écrit :
Hello,

I've recently found it convenient to do something like this:
(snip)
In other words, using the optparse object to hold as attributes everything
needed by all the functions and methods in the module, and simply passing it
holus bolus to all them and just pulling out what's actually needed inside
the function, even adding new attributes or reassigning old ones along the
way.

Congratulations, you just reinvented globals and spaghetti-code.

(snip)

My question is: is this horribly inefficient or otherwise wrong?

The only thing I can say is that I hope I'll *never* have to maintain
your code.
 
J

John O'Hagan

John said:
In other words, using the optparse object to hold as attributes
everything needed by all the functions and methods in the module, and
simply passing it holus bolus to all them and just pulling out what's
actually needed inside the function, even adding new attributes or
reassigning old ones along the way.
[...]

My question is: is this horribly inefficient or otherwise wrong?

Partially, I do the same - passing around the opts-object so that I
don't have to e.g. pass verbosity-levels around explicit.

*BUT* what I would *never* do is to assign to the options-object! If you
need state that changes and is something else that configuration, use a
class and instance-attributes together with self to communicate and
alter that state. The reason is simply that you don't do it much
differently now, but the options-object gets a god-like status it
shouldn't have. Without tracing all calls in the correct order, it is
impossible to say what state the object might have.

I see your point but I want to be clear on the correct approach: to take
my original example, is the following better:

class State:
pass
state = State()
...
def function_two(options, state):

bar = options.option_two
state.old_option_two = bar
bar = bar * foo
state.new_option_two = bar

def function_three(options, state):
blop = state.old_option_two
...
?
[...]

Make function_one and function_two methods of class "State" (you'd
obviously like to rename it something more useful then)

That hadn't occurred to me, as the real functions concerned (about a dozen)
deal with different kinds of objects, it's just the (50+) options (and things
derived from the options) that they need to share, to varying degrees. I
guess I had thought of a class as something that deals with a particular type
of "data". But I see that this is the way to go.
Options are something that is given by the user. They should be considered
read-only. Any state that drives your logic should be explicit, and if
several functions rely on shared state, then a class is the usual answer.
Alternatively, you can of course pass explicit arguments.
[...]
Thanks for the helpful replies.

Regards,

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top