Live data from Hacker News

A few things to remember while coding in Python

satyajit.ranjeev.in

51–60 of 146 posts

Re: A few things to remember while coding in Python

#51
post #9

Till now I had never seen Ellipsis. It seems very similar to slice notation [:]. Found an StackOverflow comment [1] that has more details about usage of Ellipsis in slicing higher dimensional array numpy. [1] http://stackoverflow.com/questions/118370/how-do-you-use-the...

The only way in which Ellipsis can be useful is to save one character by using it instead of pass in Python3, like:

    def foo():
        ...
It is really highly unusual and I wouldn't recommend the practice shown in the blog post at all as this is not a common pattern.

Re: A few things to remember while coding in Python

#52
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 it has a __missing__ method to insert values computed by a factory function and that int() with no arguments returns zero).

* The Counter version provides helpful methods such as "most_common(n)".

2). An ellipsis in Python is normally used in a much different way than shown in the article (it's used for an extended slice notation in NumPy).

Re: A few things to remember while coding in Python

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

This also explains when mutable defaults are not a problem: when they are not mutated in the function's body. There's nothing wrong with this:

  def f(seq=[]):
    for x in seq:
      # do something

Re: A few things to remember while coding in Python

#55
post #2

Another handy one I saw recently: varname, = [x for x in l if predicate_with_single_truth_value(x)] The comma after varname is an implicit assert that the list comprehension only contains one element.

A better way: varname = (x for x in l if predicate_with_single_truth_value(x)).next()

Re: A few things to remember while coding in Python

#56
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)

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.

Re: A few things to remember while coding in Python

#57
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…

the D language supports that kind of syntax nums.filter!(i => i%2 == 0).map!(i => i/2);

To elaborate, this is because of D's Uniform Function Call Syntax (http://www.drdobbs.com/blogs/cpp/232700394) - any function that takes an object as first argument can be called as though it were a method of that object; "map" and "filter" are actually functions in the std.algorithm module. It's a pretty neat trick and although in principle it could make things harder to reason about I haven't had any problems with it so far.

Re: A few things to remember while coding in Python

#58
post #30

Earlier quoted context omitted.

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, you…

It's not designed to be useful

By useful he means mucking up your program in totally unexpected ways.

He's being nice about it being a silly decision to have it behave that way. The entire post reads more like a list of unexpected things that will bite you in the ass.

Re: A few things to remember while coding in Python

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

This also explains when mutable defaults are not a problem: when they are not mutated in the function's body. There's nothing wrong with this: def f(seq=[]): for x in seq: # do something

Yes but no. In two month, when the function has grown, the next coder may not notice the issue and start mutating the default in the function body. Then you have a hidden killer bug.

Pass all code under pylint scrutiny, comply to its complains or adjust its rules, do it early. That is the recommendation I wish all devs could read.

Re: A few things to remember while coding in Python

#60
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…

the D language supports that kind of syntax nums.filter!(i => i%2 == 0).map!(i => i/2);

so does Scala

    stuff.filter(_ % 2 == 0).map(_ / 2)
and C#, demonstrating that this isn't some obscure feature that only language geeks care about:

    Stuff.Where(x => x % 2 == 0).Select(x => x / 2)
My point isn't that this sort of syntax is new and novel, it's just that in Python it's annoyingly inconsistent. There are reasons where you would want to use type-class style modules to structure your code in a certain way, but I do not think python's map() filter() reduce() and len() qualify as these cases
Post reply on HN