Hacker News new | ask | show | jobs
by masklinn 4862 days ago
To add to other comments, things the author could have expanded upon:

* vararg keyword arguments (kwargs)

* Keyword-only arguments (Python 3)

* help, vars, a few other nice introspective builtins

* Assignment unpacking (multiple names as left-hand side of an assignment)

* The strangest "first blush" difference between Ruby and Python, or at least the one which I found oddest when I first started switching, is that a new Ruby class is defined from the `class {Name}` line, the whole body executes in the context of the already-created class. Not so in Python, the class object will only exist once the body has finished executing.

* No mention of generators? Also outer v inner iteration is a pretty big split between two otherwise similar languages.

Mistake-ish

* obj.__dict__ -> vars(obj)

* obj.__class__ -> type(obj)

* Python's lambdas are not one-line, they're one-expression. The reason you "can't do [this] in Python" is that if:elif:else: is a statement, so doesn't fit in lambdas. But you can have arbitrary complex code in lambdas aside from that, by following http://codon.com/programming-with-nothing. For instance you can (although you should not) write:

    map(lambda num:
            0 if num % 3 == 0 else
            num * 2 if num % 4 == 0 else
            num,
        range(1, 6))
* Author talks about methods a lot. They're not methods, a method is part of an object. They're functions. Granular functions, inner functions, ...

* We generally don't say Python values "evaluate to False", we say they're falsy: they're never equal to False (outside of False and — for historical reasons — 0), they're just equivalent when evaluated in a boolean context (or passed to `bool()`). Also, the list is way incomplete: any Python type defines its own "falsiness" by implementing __bool__ (or __nonzero__ in Python 2)

* Python's reflection and metaprogramming are roughly on par with Ruby's, their lack of use is more of a cultural artefact (possibly historically motivated) than a technical one. Consider adding methods to existing types for instance. You can do it in Python (on python-defined types), you just very rarely do, it's not in the culture to do something like that. Same with using metaclasses, it's done but it generally isn't the first thing a Python developer will reach for, aside from things like registering classes on the fly/on definition

Odd comments:

* Ruby mixins, as far as I know, work by injecting the module in the inheritance chain somewhere above the new class. MI is clearer and just as powerful.

3 comments

> Python's reflection and metaprogramming are roughly on par with Ruby's, their lack of use is more of a cultural artefact than a technical one.

+1 on everything you listed, but especially this. You _do_ see some examples of monkey-patching in Python, but at least in my very limited experience, it tends to be much less prevalent in Python than it does in Ruby. Any data to contradict this is welcome, however.

This also might fall along the lines of "you usually don't want to do this, because anyone else who works on the codebase afterwards will hate you for it."

Monkey-patching also makes it harder to easily determine which names come from which source files, which is one of the strengths of Python code: Python's import system or explicitly using "self" make Python much superior to other languages.

Is Python's multiple inheritance model still wonky? For example, I remember this being a "broken" (that is, incompatible with MI) class:

    class BaseClass:
        def __init__(self):
            do_important_work()
It's broken, because this class doesn't expect to have any superclass other than Object, and hence doesn't call

    super(self, BaseClass).__init__(*args, **kwargs)
or something like that (which by the way, is super awkward syntax, repeating both self and BaseClass). But if it's subclassed as one of multiple base classes the parent classes might not get their __init__ methods called (or you might not get your __init__ called, because they forgot to call super().__init__ as well, and the superclass inheritance order ended up putting them in front of you).
> which by the way, is super awkward syntax, repeating both self and BaseClass

In Python 3, you can write just `super()`, even though I personally prefer the verbose (and thus explicit) way.

In single-inheritance cases, there's actually no benefit of using super(), so using `BaseClass.__init__(self, args, *kwargs)` is even more explicit.

I screwed up the markup there, it's supposed to be

    BaseClass.__init__(self, *args, **kwargs)
Is this what the old-style and new-style class distinction was meant to be used for?
Multiple Inheritance is one of those things I really just cannot understand. From my experience, inheritance is almost always the wrong solution. Composition being the correct tool.

Mixins are based on the concept of composition. In my opinion, more instances of inheritance should be composition than not. I strongly suspect that many cases for multiple inheritance are actually confusion around when to use composition.

Admittedly I have little experience with languages that support multiple inheritance. Do you have an example where multiple inheritance is a clear solution to a problem that you faced?

I wouldn't say mix-ins are based on the concept of composition. The mix-in is not a discrete object that's part of the composition of the class.
Their effect of adding a mixin is similar to macros, but they provide the same abilities as composition. I wouldn't be surprised to find that mixins were based off of macros. They work really well in places where I would compose behaviour into an object.