[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