Live data from Hacker News

A few things to remember while coding in Python

satyajit.ranjeev.in

121–130 of 146 posts

Re: A few things to remember while coding in Python

#121

Earlier quoted context omitted.

It's a mistake. Default values for optional parameters don't act that way in any other language I know of, including Common Lisp, in which functions are also firstclass.

It's most certainly not a mistake; Python 3 would probably have fixed it, if it were. It is an (admittedly, strange) side effect of the way 'def' works.

IMO mutable default arguments should be forbidden just as mutable keys are not accepted in dictionaries. All of the examples which claim to have a use-case for mutable default values can be rewritten with more explicit (thus more pythonic) constructs.

Re: A few things to remember while coding in Python

#122
post #109
post #5

It's worth explaining why mutable defaults are bad. The problem with mutable defaults is that they are evaluated once only when the function is defined. Each time the function is called you'll be using the same mutable variable that was created during function definition.

> 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

That's an unpythonic hack. It is possible to have an explicit static variable using function attributes; another way is to use a proper memoization decorator which factors this out.

Re: A few things to remember while coding in Python

#123
post #109
post #5

It's worth explaining why mutable defaults are bad. The problem with mutable defaults is that they are evaluated once only when the function is defined. Each time the function is called you'll be using the same mutable variable that was created during function definition.

> 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.

Re: A few things to remember while coding in Python

#124
post #80

Earlier quoted context omitted.

Functions (methods) are first class objects also in Ruby: methods are instances of the class Method, while Procs are a lightweight alternative. Default arguments in Ruby are not mutable in any kind of function object, be it a lambda proc, a regular proc, or a method. You can use a mutable default argument as an ersatz static variable, e.g. for memoization.

> Default arguments in Ruby are not mutable in any kind of function object Maybe I misunderstood you, but they are perfectly mutable: class A attr_accessor :a def initialize @a = [] end def b x = a x # obj.b # => [1] obj.b # => [1, 1] obj.a # => [1, 1] If you mean "inline default arguments are not mutable", that's not true either. What is true is that the default argument is evaluated when the function is called, not…

And this is expected behavior. What is unexpected is when this behavior is afforded to new list or dictionary arguments in Python, just as it would be unexpected to say

    ruby> class A; end
     => nil 
    ruby> def foo(bar = A.new); return bar; end
     => nil 
    ruby> foo
     => # 
    ruby> foo
     => #
and get back the same object each time `foo` is called in Ruby.

I've even seen a major Python library with this bug (I'm sorry, I don't recall which off-hand). It's really surprising behavior for new Python devs.

Re: A few things to remember while coding in Python

#125
post #110

Earlier quoted context omitted.

There are a few use cases for default variables on effbot's site: http://effbot.org/zone/default-values.htm Basically, sometimes you do want to reuse the mutable between function calls, and in those cases it can save a fair bit of code passing it in repeatedly.

Good coverage. I use it quite often for cache dictionary, it's much simpler API and overall code, than creatng a new class for it. Demo snippet from effbot's site: def calculate(a, b, c, memo={}): try: value = memo[a, b, c] # return already calculated value except KeyError: value = heavy_calculation(a, b, c) memo[a, b, c] = value # update the memo dictionary return value

This seems a bit leaky. You're exposing the caching mechanism in the method signature(yeah, ok, in practice it's unlikely to be a problem).

Re: A few things to remember while coding in Python

#126

Earlier quoted context omitted.

It's called destructuring assignment. It's been around for a while. http://dunsmor.com/lisp/onlisp/onlisp_22.html

I mean why would you want to allow both list and tuple syntax for exactly the same semantics, when either of them would be enough.

I just wish we had destructing assignment for other types as well. And maybe a proper pattern matching!

Re: A few things to remember while coding in Python

#127
post #117

Earlier quoted context omitted.

Is that clean and neat, or weird and inscrutable? Will it be clear to /anyone/ reading that code what it's doing?

I'm a Python newbie, and that code was immediately clear and obvious to me when I read it. I won't say it would be clear anyone that reads it, because we live in a world where people who claim to be programmers can't do fizz buzz.

I'm a Python veteran, and, if you do it like this, I'll shoot you.

Add a @memoize decorator and do it there, you need to always be as obvious as possible. Compare:

    @memoize
    def fibonacci(n): pass
    
    def fibonacci(n, memory=[]): pass
You don't even need documentation for the first example.

Re: A few things to remember while coding in Python

#128

Earlier quoted context omitted.

Ah. These are the little assumptions that keep blowing off my feet. Thanks.

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'

Re: A few things to remember while coding in Python

#129

There is a builtin function called `reversed`. You'd better remember that than the "useful" [::-1] idiom. The recommendation on `iteritems` had better be generalized to include `iterkeys`, `itervalues`, and other opportunities for using iterators rather than building lists. A note that the 'iter...' versions are removed in Python 3 (because iterator behaviour becomes the default) would be appropriate here. In relatio…

list(reversed(xs)) to make a copy rather than a view, though

Re: A few things to remember while coding in Python

#130
post #28

Earlier quoted context omitted.

I agree with the spirit of your argument. In fact, I almost came here to write a parallel comment: I'm really not sure that reversing the list 'a' with 'a[::-1]' is better than 'reversed(a)', which usually effectively does the same thing, but whose meaning is much more obvious. But, while I agree with your general point, in the specific case of 'defaultdict', I differ. I use 'defaultdict' all the time and I'm glad it…

reversed(a) and a[::-1] are not equivalent. The former produces an iterator over the given list (with all the mutability dangers that come with it), while the latter produces a copied list. For plain iteration, you're correct, reversed() is better (similar to how xrange vs. range was back in the day); however, for reversing something and keeping it around, the slice syntax is better. >>> reversed([1, 2, 3]) >>> [1, 2…

list(reversed(a))
Post reply on HN