On Wed, Apr 29, 2015 at 4:25 PM, Cecil Westerhof <ce...@decebal.nl> wrote: > Op Tuesday 28 Apr 2015 10:06 CEST schreef Chris Angelico: >> (note that I'm avoiding the multiple-argument syntax which doesn't >> work in Python 3; > > I already did this with print. Are there other statements I have to > take care for the possible problems with Python 3? I do not use Python > 3, but that does not mean it is not a good idea to make my modules > work with it.
As long as you can require a minimum Python version of 2.7 (usually not hard these days; older Pythons are still around, but diminishingly, and you can simply choose not to support them), it's not too hard to make your code basically compatible. The biggest change will be the bytes/unicode distinction; you can adorn your byte strings with b"..." and your Unicode strings with u"...", but the hard part is keeping track in your head of which one is which. For a lot of programs, it's not difficult; ASCII strings fit happily into either bytes or Unicode, so the bulk of your strings can be left unadorned. >> if ParameterError is a subclass of ValueError you >> could use that instead, but ValueError works) > > Was the wrong error: should have been TypeError. I find this strange: > Python is compiled, but I get only an error when this statement is > reached. As Python code gets compiled, names get turned into either locals or external lookups. You can inspect a function interactively: >>> def checkme(x): ... if x < 0: raise BotchedError("Oops") ... return x + 1 ... >>> checkme.__code__.co_names ('BotchedError',) >>> checkme.__code__.co_varnames ('x',) Local variable are turned into special slots, matching co_varnames; global name lookups are done at run time. This allows mutual recursion: def func1(x): if x % 2: return x - 1 return func2(x + 2) def func2(x): if x % 3: return x return func1(x - 4) At compilation time, func1 has a global name reference that can't be resolved... but by the time anyone gets to calling it, the module has gained a func2, and all is well. If you want to check your code for name mistakes, you could do something like this: # checker.py import sys def check_module(module): mod = sys.modules[module] for attr in dir(mod): thing = getattr(mod, attr) try: names = thing.__code__.co_names except AttributeError: continue # Not a function for name in names: if name not in dir(mod) and name not in dir(mod.__builtins__): raise NameError("Function %s refers to %s which doesn't exist" % (attr, name)) Then you just put this line at the bottom of your code to see if there are any potential problems: import checker; checker.check_module(__name__) Alternatively, you could build functionality like this into a linter or other code quality confirmation. For most code, this will be a safe check; it is theoretically possible for a module to grow a new attribute between the end of module execution and the actual calling of a function (which is why the interpreter itself doesn't check like this), but it's sufficiently unusual that you could safely disallow it in your style guide or source control policy. > I am of the school that it is good to check as much as possible. > (Without going over the top.) One of the key differences between the C++/Java mentality and the Python mentality is that, while both schools of thought would broadly agree with what you say here, we draw the line of "over the top" at different places. In Java code, you're expected to type-check everything; in Python code, just use it, and if the caller gives you the wrong data type, that's his problem, not yours. In Java code, exceptions are there to be carefully documented - "this function might raise this/these exception(s)", and its callers have to decide at compilation time whether they're going to handle them or let them bubble. In Python code, unexpected exceptions are generally expected to bubble all the way up to a generic handler - for most applications, that means printing the exception to the console and terminating. You deal with things you know how to deal with, and any weird things that happen, again, not your problem. Neither philosophy is fundamentally wrong, but other Java programmers will get very annoyed at you if you adopt a Python style in Java code (using RuntimeError for everything, and checking nothing), and your Python code will get unnecessarily verbose and heavy if you adopt a Java style in Python code. It's up to you to decide how worthwhile it is, but I recommend at least giving the Python style a try (pun not intended); you may well like it, or you may find that you want at least a bit more pre-checking, but either way, you'll know why. All the best! ChrisA -- https://mail.python.org/mailman/listinfo/python-list