41

I just started learning Python a few months ago, and I'm trying to understand the differences between the different __get*__ methods:

__get__
__getattr__
__getattribute__
__getitem___

And their __del*__ equivalents:

__del__
__delattr__
__delete__
__delitem__

What are the differences between these? When should I use one over the other? Is there a specific reason why most of the __get*__ methods have __set*__ equivalents, but there is no __setattribute__?

Zearin
  • 1,474
  • 2
  • 17
  • 36
  • 1
    The documentation doesn't list them "side by side" as in "horizontally", but it does have all of them on a single page and all except the `{get,set}item` ones (which stand out by featuring `item`) are right next to each other vertically, in two small sections. Some of those names *are* too terse/similar, but it's not as bad as you make it sound. –  Jan 28 '12 at 20:47
  • 2
    Yep, I realized about 20 minutes ago that they ARE in fact all on one page. Sorry about that—my mistake. **However:** I am still confused. I thought I was clear that I **have** read the documentation, and I’m still having trouble drawing a clear definition between the special method names. – Zearin Jan 29 '12 at 01:08

1 Answers1

48

The documentation for every method that you listed is easly reachable from the documentation index .

Anyway this may be a little extended reference:

__get__, __set__ and __del__ are descriptors

"In a nutshell, a descriptor is a way to customize what happens when you reference an attribute on a model." [official doc link]

They are well explained around, so here there are some references:

__getattr__, __getattribute__, __setattr__, __delattr__

Are methods that can be defined to customize the meaning of attribute access (use of, assignment to, or deletion of x.name) for class instances. [official doc link]

Example 1:

class Foo:
    def __init__(self):
        self.x = 10
    def __getattr__(self, name):
        return name

f = Foo()
f.x    # -> 10
f.bar   # -> 'bar'

Example 2:

class Foo:
    def __init__(self):
        self.x = 10
    def __getattr__(self,name):
        return name
    def __getattribute__(self, name):
        if name == 'bar':
            raise AttributeError
        return 'getattribute'

f = Foo()
f.x    # -> 'getattribute'
f.baz    # -> 'getattribute'
f.bar    # -> 'bar'

__getitem__, __setitem__, __delitem__

Are methods that can be defined to implement container objects. [official doc link]

Example:

class MyColors:
    def __init__(self):
        self._colors = {'yellow': 1, 'red': 2, 'blue': 3}
    def __getitem__(self, name):
        return self._colors.get(name, 100)

colors = MyColors()
colors['yellow']   # -> 1
colors['brown']    # -> 100

I hope this is enough to give you a general idea.

Community
  • 1
  • 1
Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
  • 1
    (1) I realized about 25 minutes before I found your answer that these are in fact all documented on one page. Sorry for that error in my original question. (2) **Thank you!!** The articles by Marty Alchin are written extremely well. And they clarified something huge I wasn’t getting—that `__get__` and `__set__` are supposed to be defined _in the attributes_, and not in the class! I still think all the methods in my original post could do with more differentiable names, but I suddenly feel a lot less overwhelmed. Thank you. ☺ – Zearin Jan 29 '12 at 01:18
  • 1
    @Zearin: There's a good article about [Python Attributes and Methods](http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html) maybe it can interest you. *(fixed link)* – Rik Poggi Jan 29 '12 at 11:33
  • 2
    @RikPoggi You are actually not saying, why `__get__` when we have `__getattr__` or vice verca. answer you mentioned for both are same – overexchange Jun 02 '17 at 11:16
  • Thanks for the examples and link to docs. Would be nice to explicitly mention how we get from `AttributeError` to `__getattr__` in a `# comment`, and perhaps also that, unlike `__setattr__` and `__getattribute__`, `__getattr__` is only invoked if the name is not defined, or through an `AttributeError`. At least that's my understanding. – Julian Oct 02 '17 at 12:39