[Tutor] functions first?
Alex Kleider
akleider at sonic.net
Tue Jan 27 17:39:17 CET 2015
On 2015-01-27 03:18, Steven D'Aprano wrote:
> On Mon, Jan 26, 2015 at 06:04:10PM -0800, Alex Kleider wrote:
>> Please correct me if I am wrong, but I've assumed that it is proper to
>> define all functions before embarking on the main body of a program.
>> I find myself breaking this rule because I want to set the default
>> values of some named function parameters based on a configuration file
>> which I have to first read, hence the need to break the rule.
>> ..so my question is "is this acceptable" or "is there a better way?"
>
> I'm not really sure I understand the question correctly.
>
> As far as *design* go, there are two competing paradigms, "top-down"
> versus "bottom-up". Perhaps you are thinking about that?
>
> In top-down, you start with the part of the application closest to the
> user, say, a web browser:
>
> def run_browser():
> win = make_window()
> page = get_url(whatever)
> show_page(page, win)
>
> Then you write the next level down:
>
> def make_window()
> ...
>
> def get_url(address):
> ...
>
> def show_page(page, win):
> ...
>
> and so on, all the way down to the most primitive and simple parts of
> the application:
>
> def add_one(n):
> return n+1
>
>
> In bottom-up programming, you do the same, only in reverse. You build
> the most primitive functions first, then add them together like Lego
> blocks, getting more and more complicated and powerful until you end up
> with a fully-functioning web browser.
>
> Personally, I think that in any real application, you need a
> combination
> of both top-down and bottom-up, but mostly top-down. (How do you know
> what primitive operations you will need right at the start of the
> design
> process?) Also, many of the primitive "Lego blocks" already exist for
> you, in the Python standard library.
>
> If you are talking about the order in which functions appear in the
> source file, I tend to write them like this:
>
> === start of file ===
> hash-bang line
> encoding cookie
> licence
> doc string explaining what the module does
> from __future__ imports
> import standard library modules
> import custom modules
> metadata such as version number
> other constants
> global variables
> custom exception types
> private functions and classes
> public functions and classes
> main function
> if __name__ == '__main__' code block to run the application
> === end of file ===
>
>
> All of those are optional (especially global variables, which I try
> hard
> to avoid). Sometimes I swap the order of private and public sections,
> but the main function (if any) is always at the end just before the "if
> __name__" section.
>
>
> As far as the default values go, I *think* what you are doing is
> something like this:
>
> f = open("config")
> value = int(f.readline())
> f.close()
>
> def function(x, y=value):
> return x + y
>
>
>
> Am I right?
Yes, this is indeed what I was doing (but then on reflection,
became uncertain about the wisdom of doing it this way- hence
the question.)
>
> If so, that's not too bad, especially for small scripts, but I think a
> better approach (especially for long-lasting applications like a
> server)
> might be something like this:
>
> def read_config(fname, config):
> f = open(fname)
> config['value'] = int(f.readline())
> f.close()
>
> PARAMS = {
> # set some default-defaults that apply if the config file
> # isn't available
> value: 0,
> }
>
> read_config('config', PARAMS)
>
>
> def func(x, y=None):
> if y is None:
> y = PARAMS['value']
> return x + y
>
>
>
> This gives lots of flexibility:
>
> - you can easily save and restore the PARAMS global variable with
> just a dict copy operation;
>
> - you can apply multiple config files;
>
> - you can keep multiple PARAMS dicts (although as written, func only
> uses the one named specifically PARAMS);
>
> - read_config can be isolated for testing;
>
> - you can re-read the config file without exiting the application;
>
> etc.
>
>
> Does this help?
Yes, very much so.
Thank you again!
I use the docopt module to collect command line options and then
configparser to read a file.
Some of the values (such as a port number, for example) must then be
adjusted. An example is
a port number which I want to convert from "5022" to ":5022" if it's a
non standard port or
to "" if it is the standard "22" so it can then be used as a string
format parameter.
Perhaps I should be doing this in the same place as I set up the string
rather than where
I populate the 'config' and 'PARAMS' dictionaries?
Sincerely,
Alex
More information about the Tutor
mailing list