Live data from Hacker News

A few things to remember while coding in Python

satyajit.ranjeev.in

131–140 of 146 posts

Re: A few things to remember while coding in Python

#131
post #95

Overall, this is a nice post. There are two quibbles though. 1). For the most part, "c = collections.Counter()" is almost always better than "c = defaultdict(int)" * Counter only supplies missing values rather than automatically inserting them upon lookup. * The Counter version is much clearer about what it is trying to do. The defaultdict version is cryptic to the uninitiated (understanding it entails knowing that i…

Unfortunately, Counter is not available before 2.7, so for many people it's a bit too early to require it.

Two years old is a long enough.

Re: A few things to remember while coding in Python

#132
post #115

Earlier quoted context omitted.

I don't buy this explanation. Actually, this is not a design flaw, and it is not because of internals, or performance. It comes simply from the fact that functions in Python are first-class objects, and not only a piece of code. Why in Common Lisp defaults behave the way one would expect, then? Functions are also first class, but defaults are evaluated at every call.

I don't know CL, but in python function definitions can be executed multiple times... at the top level this happens at module import, so it ends up being only once. But in nested definitions, e.g. def foo(): def bar(): ... return bar foo() == foo() # false Two different function objects are created. If, in the above examle, bar took a pram thelist=[], each call to foo would produce a bar function with a different lis…

The fact that definition can be evaluated many times is not really relevant here. What is important is how one specifies language's semantic -- for instance, Common Lisp: The Language, 2nd edition book (I don't own ANSI standard) says:

When the function represented by the lambda expression is applied to arguments, the arguments and parameters are processed in order from left to right. (...) If optional parameters are specified, then each one is processed as follows. If any unprocessed arguments remain, then the parameter variable var is bound to the next remaining arguments, just as for required parameter. If no arguments remain, however, then the initform part of the parameter specifier is evaluated, and the parameter variable is bound to the resulting value (...).

The CLTL2 specifies that the form representing the default value of optional parameter shall be evaluated every time the parameter is not provided.

Re: A few things to remember while coding in Python

#133
post #11

halve_evens_only = lambda nums: map(lambda i: i/2, filter(lambda i: not i%2, nums)) I still find it rather silly that python doesn't supper a nice list map/filter; it could be so much nicer nums.filter(lambda i: i%2 == 0).map(lambda i: i/2) If they did, even including the annoyingly long-to-type "lambda". List comprehensions are cool and all, but do not really scale visually (i.e. get rather messy) when you have more…

Rust typeclasses solve this problem; you can create a suite of methods with syntax like this:

    impl methods for [T] {
        fn filter(f : fn(T)->bool) -> [T] { ... }
        fn map(f : fn(T)->U) -> [U] { ... }
    }
And then you can call it with syntax like:

    println(#fmt("%?", [ 1, 2, 3 ].map { |x| x + 3 }));
    // prints "[ 4, 5, 6 ]"
The methods are properly scoped, so code that isn't in your module needs to import your methods to use them. That way, you avoid introducing strange action-at-a-distance in your code.

Re: A few things to remember while coding in Python

#134
post #95

Earlier quoted context omitted.

Unfortunately, Counter is not available before 2.7, so for many people it's a bit too early to require it.

Two years old is a long enough.

OSX 10.6.8 still has Python 2.6 as the system Python.

Re: A few things to remember while coding in Python

#136

Earlier quoted context omitted.

It is these cases that brought the ternary operator to Python: def f(x=None): x if x is not None else []

you forgot 'return'

Yeah, I guess my typing went into "lambda mode" since it was a one liner.

Re: A few things to remember while coding in Python

#137
post #109

Earlier quoted context omitted.

> It's worth explaining why mutable defaults are bad They can also be good. Here's an example from the Reddit discussion, showing how a mutable default can be used to very neatly and cleanly add memorization to a function: def fib(n, m={}): if n not in m: m[n] = 1 if n

Cleverness like this makes you feel warm and fuzzy inside right up to the point where someone decides to actually pass that second argument to your function.

Well in Python 3 you can warn them:

    def fib(n, m:"donotusethisparameter"={}):

Re: A few things to remember while coding in Python

#138
post #108

Earlier quoted context omitted.

It is these cases that brought the ternary operator to Python: def f(x=None): x if x is not None else []

Yes, but why? Actually, it's No, because python culture aims to use one way to do thing, the least surprising one. In this case it's: def f(x=None): if x is None: x = []

Because that "if" is a statement whereas the ternary expression is, well, an expression. There are places expressions can be used that statements can't (eg lambdas) and that x or [] won't work (eg when x is False).

That said, people still seem to favor your form as the more Pythonic way. Personally, I think that's just because the ternary expression is relatively new.

Re: A few things to remember while coding in Python

#139
post #95

Overall, this is a nice post. There are two quibbles though. 1). For the most part, "c = collections.Counter()" is almost always better than "c = defaultdict(int)" * Counter only supplies missing values rather than automatically inserting them upon lookup. * The Counter version is much clearer about what it is trying to do. The defaultdict version is cryptic to the uninitiated (understanding it entails knowing that i…

Unfortunately, Counter is not available before 2.7, so for many people it's a bit too early to require it.

There is a Python2.5 backport of collections.Counter() at http://code.activestate.com/recipes/576611/

Re: A few things to remember while coding in Python

#140

Earlier quoted context omitted.

Also Exceptions should be used in "exceptional" circumstances and not as part of normal flow.

One exception (teehee!) to the rule: file operations and other things where atomicity matters. Example code: if not os.path.exists("foo"): os.mkdir("foo") That introduces a race condition. If foo does not exist on the first line but is created by something else on the second line then this will raise an exception. The proper code is: import errno try: os.mkdir("foo") except OSError as exc: if exc.errno != errno.EEXIS…

Thank you for pointing that out, I've just changed some code :)
Post reply on HN