

Python quirks - ktf
http://www.lshift.net/blog/2009/10/29/python-quirks

======
makecheck
As far as the "os" versus "os.path" question; this is hinted in the Python
documentation for modules that "os.path" can be an alias of, such as
"os.posixpath"; there, it recommends "import os" and then referring to
"os.path". In other words, there's no need to "import os.path".

------
lepht
Pretty good list, although I'm not sure how else you would expect 'finally' to
function?

~~~
majke
It's not that I expect it to work differently. It's more like: "oh, you can do
that, that's interesting".

And the question is, how to exploit this behaviour. Does it mean that I can
effectively rewrite return values? Can I access the original return
parameters? Can it be used as a substitute of goto? (cascaded loops, that end
up in return, which is than captured by finally)

------
thwarted
This is kind of a weird list. I'm just learning python, but I don't know if
any of these are quirks or just the result of not reading the documentation,
or it not being like My Favorite Language(tm).

 _Sort returns nothing_

I expect the result of calling the sort() method on an array to sort the array
that it was called on. Since this example is calling sort on a literal array,
there's no way to access the array after it's sorted.

 _Tuples constructor_

I agree this is a quirk, as the result of the overlapping choice of
parenthesis for the tuple literal and as expression precedence. The leading
star on the _args argument puts all the arguments into a single variable as a
tuple. foo(1,2) has two arguments, which sets args to (1,2), and the
representation for that is "(1,2)". foo((1,2)) as only one argument, a two
element tuple, and the representation for that is "((1,2),)", the last comma
being needed to disambiguate this as one element tuple where the first element
is also a tuple. In the second group, both foo(1) and foo((1)) have only one
argument, in the latter case the argument is an arithmetic expression with no
operators that evaluates to the number 1, and the literal representation for a
single argument tuple, the args variable, is "(1,)".

The % operator takes two operands. The RHS operand is a list or tuple with the
same number of elements as there are %expansions in the LHS. Only one
%expansion is given in the format string on the LHS, but a two element tuple
has been given on the RHS.

_Print is magical*

print is a statement. pprint.pprint is a function. Function arguments must be
enclosed in parens. This isn't perl.

 _Inconsistent get interface_

This is documented, shows up in ipython's "help getattr". getattr takes an
optional third argument that is returned if the attribute doesn't exist which
would regularly raise an exception.

 _Inconsistent select/poll interface_

The only thing that is inconsistent here is how the timeout value is specified
compared to the underlying UNIX implementation these are wrappers for. In the
UNIX interfaces, select and poll take a structure that allows both seconds and
fractions of a second, and epoll takes an integer. While I suppose this is
confusing, these all have different usage patterns and different APIs, so it's
not like you can just replace the call to select with poll and not have to
refactor the rest of the code. This could be cleaned up, but it's most likely
not worth it since the ranges of the timeout values reflect the most common
ranges people are expecting to use.

 _Circular Imports_

This can be overcome by remembering that modules, classes and functions are
defined at run time, that an object can be referenced even though it's not
finished being executed.

 _999+1 is not 1000_ and _What is the value of one?_

I'm not sure why you'd use the _is_ operator to test equality of integers,
when _is_ is meant to test object equality. In the same way it is suggested to
_not_ compare strings and numbers.

 _The order of unpacking_

Using the same variable name multiple times on the LHS when unpacking should
be undefined, because the reason to do that would be because you don't care
about the values that are being unpacked into the same variable. I can not
think of a reason you should be encouraged to write a function that takes
multiple arguments that can not all be accessed, if you wanted to do that, you
should define the function's arguments as _args so they get eaten up, it's
more obvious that some of them are optional than using the same variable name
that ends up hiding one.

The example of foo(a=1, b=2, _args, __kwargs) is definitely confusing, but
then this would seem to be a confusing API anyway -- it would be best not to
write a function like that. What I expect to happen here is that a and b have
default arguments no matter what the kwargs are, but you can't specify a
kwargs entry named a (as in foo(3,4,6, a=4)) without it raising "TypeError:
foo() got multiple values for keyword argument 'a'".

 _Multi line strings_

python statements don't end with semicolons, so you need to escape the
newline, which would mark the end of the assignment expression in the first
example. In the second, the RHS of the assignment is an expression enclosed in
parens, which doesn't end until it forms a complete expression with the
closing paren. Whitespace between strings concatenates the strings, so but the
newline ending the expression in the first example needs to be escaped so it's
interpreted as whitespace and not as the end of the statement.

 _Finally finally is interesting_

Watch out for this. If try blocks are nested, it seems that a nested finally
with a return keeps an enclosing except block from executing:

    
    
        def x():
            try:
                try:
                    print "try"
                    raise Exception
                finally:
                    print "finally"
                    return 1
            except:
                print "except"
                return 2
    
        print x()
    

I actually prefer to nest try blocks like this to get more control over the
order of execution of the finally and except blocks and make it more obvious
as to what the intended order of execution is.

 _List comprehensions, kind of._

I actually like having to explicitly have a literal list comprehension in the
for-loop syntax. I'm not sure that the lack of punctuation increases
readability: the _if_ in the suggested (second) syntax kind of gets lost. For
maximum readability, the list comprehension might be best split into a
separate expression statement rather than trying to take on perl in the
longest line department.

I actually find python to be much more consistent and does the expected thing
much more often than some other languages (ahem, I'm looking at you, PHP). I
just hope that as I go deeper, using it remains refreshing.

