Re: [Tutor] functions first?
On 2015-01-27 16:10, Steven D'Aprano wrote: On Tue, Jan 27, 2015 at 08:39:17AM -0800, Alex Kleider wrote: 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? I see the basic problem as this: - you have config settings (command line options, config files) which by their nature are always strings - furthermore they are strings in a format designed for human use rather than machine use - by the time your function uses them, they need to be converted from human-format to machine-format. That last step might involve a type conversion like int(s), trimming whitespace, or more complex operations. The most obvious way to do them is to apply the operation after reading the config value but before storing it in the params dict. If that works, I wouldn't add complexity where it isn't needed. If it doesn't work for you, I think you need to explain what the problem is before we can suggest a better design. Again, thank you very much. I'll do as you suggest above and see if I can make it work. Alex ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
On Tue, Jan 27, 2015 at 08:39:17AM -0800, Alex Kleider wrote: > 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? I see the basic problem as this: - you have config settings (command line options, config files) which by their nature are always strings - furthermore they are strings in a format designed for human use rather than machine use - by the time your function uses them, they need to be converted from human-format to machine-format. That last step might involve a type conversion like int(s), trimming whitespace, or more complex operations. The most obvious way to do them is to apply the operation after reading the config value but before storing it in the params dict. If that works, I wouldn't add complexity where it isn't needed. If it doesn't work for you, I think you need to explain what the problem is before we can suggest a better design. -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
On 2015-01-27 00:15, Alan Gauld wrote: On 27/01/15 02:04, 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. No, you can do it either way round. Top-Down or Bottom-Up as they are known. Usually its a muxture of both. But most folks like to have a running program at all times. So you might write the function headers with dummy bodies then write the main code that calls the functions. Then go back and fill in the functions I've just realized where the confusion arises. As Steve guessed, I was talking about the order in which they appear in the file, not the order in which they were written. Only when this light went on did I realize why I had inadvertently precipitated a discussion of top down vs bottom up design. Sorry about the confusion. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
On 2015-01-26 22:30, Ben Finney wrote: Alex Kleider writes: 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 would say rather that as much code as possible should be in small well-defined functions, with the “main body” a tiny and trivial call to a function. That way, all the code is easily tested by unit testing tools. 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. Module-level constants are fine, and they obviously need to be bound before the definition of the function which uses them for parameter defaults. But if they're not constants – as implied by your statement you read them from a configuration file – then they should not be in the function definition, because reading the configuration file should itself be encapsulated in a well-tested function. Thanks for your well reasoned advice. You are of course correct in that if they are read from a configuration file then they are not constants but in a sense they are, at least for the life of the current program run. I'm probably going to go with the way Steve recommended which is to use global dictionaries to contain the command line arguments (which docopt already does) and configuration values (which are also placed into a dictionary by configparser) and then use those dictionaries within functions that need them rather than setting default named parameters for the functions. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
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 ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
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? 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? -- Steve ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
On 27/01/15 02:04, 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. No, you can do it either way round. Top-Down or Bottom-Up as they are known. Usually its a muxture of both. But most folks like to have a running program at all times. So you might write the function headers with dummy bodies then write the main code that calls the functions. Then go back and fill in the functions one at a time, for example. eg. A trivial example: ### pass 1 def sayHello(msg): pass def getGreeting(prompt): return "hello world" def main(): greeting = getGreeting("What to say: ") sayHello(greeting) if __name__ == "__main__": main() ### pass 2 ## def sayHello(msg): print(msg) def getGreeting(prompt): return "hello world" def main(): greeting = getGreeting("What to say: ") sayHello(greeting) if __name__ == "__main__": main() ### pass 3 ## def sayHello(msg): print(msg) def getGreeting(prompt): return input(prompt) def main(): greeting = getGreeting("What to say: ") sayHello(greeting) if __name__ == "__main__": main() HTH -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] functions first?
Alex Kleider writes: > 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 would say rather that as much code as possible should be in small well-defined functions, with the “main body” a tiny and trivial call to a function. That way, all the code is easily tested by unit testing tools. > 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. Module-level constants are fine, and they obviously need to be bound before the definition of the function which uses them for parameter defaults. But if they're not constants – as implied by your statement you read them from a configuration file – then they should not be in the function definition, because reading the configuration file should itself be encapsulated in a well-tested function. -- \ “It is the integrity of each individual human that is in final | `\examination. On personal integrity hangs humanity's fate.” | _o__) —Richard Buckminster Fuller, _Critical Path_, 1981 | Ben Finney ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] functions first?
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?" thks Alex ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor