Hacker News new | ask | show | jobs
by btown 1711 days ago
https://blog.peterlamut.com/2018/11/04/python-attribute-look... is a great overview of how this works. Start with the summary at the end!

The really cool thing about this, how descriptors have their __get__ called, is that methods are implemented this way. So when you access instance.method(), it’s a normal lookup for the attribute named “method”, which is (normally) itself a descriptor, so the __get__ magic is called and this binds the method to the instance at the moment it’s needed! Then you can just call it like a normal function. It’s incredibly elegant but extremely obscure. And vital to understand if you want to dive into monkey patching, which is an incredible skill to have!

1 comments

Good article, thanks. It's worth pointing out that the summary (class hierarchy data descriptor > instance `__dict__` > class hierarchy other) only applies when looking up a normal attribute on a normal object:

* Special-method lookup (e.g. of `__add__` when you do `a + b`) works differently because it doesn't look at the instance `__dict__`, only the class hierarchy.

* Lookup on a class works differently because as well as looking at `__dict__`, it has to consider superclasses.

Much of the complexity relates to the different ways of handling the instance `__dict__`. By contrast, Ruby is able to have much simpler lookup rules because it never considers the instance, only ever the class hierarchy.

> Ruby is able to have much simpler lookup rules because it never considers the instance, only ever the class hierarchy.

“But!” I can hear people say, “I heard you could attach methods to instances in Ruby! How is this possible if Ruby never considers the instance in resolving a method call?”

Well, that’s tricky. The thing is, Ruby instances have no public members, instance variables are private (for direct access, but not in any strict way, because there are public methods called instance_variable_get and instance_variable_get on Object which…do exactly what the names say.)

But every Ruby instance conceptually has (though it doesn’t concretely have one unless you add something to it) a unique class for the instance that is the first thing in its class heirarchy. And you can add methods to that class (the instance “metaclass”, which is different than a Python metaclass) for the effect of attaching them uniquely to the instance itself.

You might even say that without classes python would be a simpler language, while keeping almost all its power :)
It's a fun dream, but without the ability for a variable to carry along with it a notion of, say, how it implements slice notation, or the ability to avoid verbose names like foo_to_repr(foo) and bar_to_repr(bar) so that names don't collide... arguably we never would have seen the rise of scientific Python! Object oriented programming is an incredibly good abstraction for a lot of real-world scenarios.