Live data from Hacker News

A few things to remember while coding in Python

satyajit.ranjeev.in

31–40 of 146 posts

Re: A few things to remember while coding in Python

#32
post #4

Earlier quoted context omitted.

Trailing commas are really easy to miss. When reading this line of code, I did not notice it immediately; I originally assumed that varname was being assigned a list. This sort of code would be very confusing when I'm just quickly reading through a procedure trying to find the potential bug.

You could also use the ,= operator, of course: varname ,= [...]

It appears to me that there is actually no such operator in Python; cf. http://docs.python.org/reference/simple_stmts.html#augmented...

Superficially it looks like an operator, but I suspect that's merely because of whitespace freedom; i.e., a, = [0] is equivalent to a,=[0] and a ,= [0].

Re: A few things to remember while coding in Python

#33

Earlier quoted context omitted.

Immature programmers. It's analogous to musicians who play everything as fast and ornately as possible.

Beat me to my equivalent answer: "java programmers."

Not a mature answer.

Re: A few things to remember while coding in Python

#34
post #28

Generally most use this: freqs = {} for c in "abracadabra": try: freqs[c] += 1 except: freqs[c] = 1 If this is really the common idiom, I'd say this is a sign that professional programming has yet to fully mature as a field. Some may say a better solution would be: freqs = {} for c in "abracadabra": freqs[c] = freqs.get(c, 0) + 1 Okay, so I understood immediately what was going on with the 2nd bit of code. Rather go…

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…

I define the default value in one place, and then the interface to my datastructure is simpler; hence as I continue writing, I can spend more of my brainpower in the problem domain.

Actually, this speaks to point: optimization should be for reading, not for writing.

Re: A few things to remember while coding in Python

#35
post #30

Earlier quoted context omitted.

Actually, if you understand the way Python is evaluated (dig in, the core is pretty transparent), it's the only behavior that makes sense in this case. It's also documented as such[1], so it's quite expected. Default parameters are still just as useful for constants, such as: def f(x=0, y="foo", z=3.14159): This, however, is a perfectly Pythonic idiom: def f(L=None): if L is None: L = [] [1]: http://docs.python.org/r…

While it seems logical when you understand what's going on, from a practical point of view I can't see how this would ever be useful. The tradeoff appears to be that the functions are first class objects. I'm not sure what the benefit here is though. Does having them as first class objects allow some useful idioms? (I'm a ruby dev but I'm genuinely curious to know what this allows you to do)

It's not designed to be useful, it just is. Functions are objects, yes, and the def statement brings them into being and assigns them to the given name in the current scope:

    >>> def f(x):
    ...     return x + 5
    >>> type(f)
    
    >>> dis.dis(f.func_code)
      2           0 LOAD_FAST                0 (x)
                  3 LOAD_CONST               1 (5)
                  6 BINARY_ADD          
                  7 RETURN_VALUE       
    >>> g = f
    >>> g(10)
    15
    >>> g is f
    True
They're just variables in the current scope. If you're quite clever, your brain is already figuring out that has some interesting implications that some libraries use:

    >>> import socket
    >>> socket.gethostbyname('www.google.com')
    '74.125.71.103'
    >>> socket.gethostbyname = lambda i: '10.0.0.1'
    >>> socket.gethostbyname('www.google.com')
    '10.0.0.1'
I will not pass judgement on monkey patching like this, just pointing out it's doable. I know for a fact Ruby can as well.

Functions just being variables has useful properties when you're doing something like fancy switch/case type things (the readability of this is questionable, but it's cool to look at it, like a Duff's device):

    >>> i = 1
    >>> { str: func1, unicode: func2, int: func3 }.get(type(i), func1)(i)
    in func3
Also consider something like this, which is how decorators work (and they're incredibly useful), sort of like a closure:

    >>> def maker(i):
    ...   def ret(x):
    ...     return x + i
    ...   return ret

    >>> f, g = maker(10), maker(100)
    >>> f(5), g(10)
    (15, 110)
I'd be surprised if Ruby couldn't do everything I just did.

Re: A few things to remember while coding in Python

#36
post #12

Generally, most use this: freqs = {} for c in "abracadabra": try: freqs[c] += 1 except: freqs[c] = 1 Who does this?!

Not only is it overly-verbose and ultimately unnecessary (as shown by the alternative that follows in the article) but this mechanism is actually broken. For instance if "freqs" were data given to you from somewhere else and "freqs[c]" happened to have a type that cannot legally have 1 added to it, you'd want to see this error. The "except:" however will absorb any and all exception types and respond to all of them by setting the value to 1.

Re: A few things to remember while coding in Python

#37
post #7
post #4

Earlier quoted context omitted.

Trailing commas are really easy to miss. When reading this line of code, I did not notice it immediately; I originally assumed that varname was being assigned a list. This sort of code would be very confusing when I'm just quickly reading through a procedure trying to find the potential bug.

Agreed. It could be written much more clearly in my opinion like this: [varname] = [x for x in l if predicate_with_single_truth_value(x)]

Good idea!

Re: A few things to remember while coding in Python

#38
post #18
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.

That seems like decidedly unexpected behaviour and makes default params far less useful.

It's like whitespace. Everybody has this reaction at first, then they get over it.

Re: A few things to remember while coding in Python

#39
post #12

Generally, most use this: freqs = {} for c in "abracadabra": try: freqs[c] += 1 except: freqs[c] = 1 Who does this?!

Not only is it overly-verbose and ultimately unnecessary (as shown by the alternative that follows in the article) but this mechanism is actually broken. For instance if "freqs" were data given to you from somewhere else and "freqs[c]" happened to have a type that cannot legally have 1 added to it, you'd want to see this error. The "except:" however will absorb any and all exception types and respond to all of them b…

Also, raising exceptions used to be quite slow, which could hurt for a sparse counting set. Don't know whether that's still the case.

Re: A few things to remember while coding in Python

#40

Probably best not to use iteritems, in python 3, it won't be there, "the dict.iterkeys(), dict.iteritems() and dict.itervalues() methods are no longer supported."

The iter* methods appear in Python 3, just without the iter prefix. Therefore it is good to use them in Python 2 because that makes it possible to translate the code automatically with the 2to3 script. Otherwise possibly superfluous list conversion might get added, e.g., list(d.keys()).
Post reply on HN