What are some rules of thumb for deciding between __get__, __getattr__ and __getattribute__?

What are some general rules for choosing which ones to implement in a given class in a given situation?

I have read the documents and understand the difference between them. Rather, I am looking for guidance on how best to integrate their use into my workflow, thereby better discovering more subtle possibilities for using them and which to use when. That kind of thing. These methods (as far as I know):

## fallback __getattr__ __setattr__ __delattr__ 

 ## full control __getattribute__ ##(no __setattribute__ ? What the deal there?) 

 ## (the descriptor protocol) __get__ __set__ __delete__ 
+6
source share
2 answers

__setattribute__ does not exist, because __setattr__ always called. __getattr__ is only called for fx if the attribute search fails through the regular channel (which is provided by __getattribute__ , so the function is always called as well).

The descriptor protocol is a little orthogonal to others. Considering,

 class Foo(object): def __init__(self): self.x = 5 f = Foo() 

The following is true:

  • fx will call f.__getattribute__('x') if it was defined.
  • fx will not invoke f.__getattr__('x') if it were defined.
  • fy will call f.__getattr__('y') if it was defined, otherwise f.__getattribute__('y') if it was defined.

The handle is called by an attribute, not an attribute. I.e:

 class MyDescriptor(object): def __get__(...): pass def __set__(...): pass class Foo(object): x = MyDescriptor() f = Foo() 

Now fx will call type(f).__dict__['x'].__get__ , and fx = 3 will call type(f).__dict__['x'].__set__(3) .

That is, Foo.__getattr__ and Foo.__getattribute__ will be used to find fx links; as soon as you do this, fx returns the result of type(fx).__get__() , if defined, and fx = y calls fx__set__(y) , if defined.

(The above __get__ and __set__ are only approximately correct, since I did not take into account the details of which arguments __get__ and __set__ really receive, but this should be enough to explain the difference between __get__ and __getattr[ibute]__ .)

Put another way, if MyDescriptor not defined __get__ , then fx will just return an instance of MyDescriptor .

+5
source

For __getattr__ vs __getattribute__ see, for example, The difference between __getattr__ vs __getattribute__ .

__get__ is not actually connected. I will quote from the official documentation for the descriptor protocol here:

The default behavior for accessing attributes is to receive, set, or delete an attribute from an object dictionary. For example, ax has a search chain, starting with a.__dict__['x'] , then type(a).__dict__['x'] and continuing with the base classes of type(a) , excluding metaclasses. If the value you are looking for is an object that defines one of the descriptor methods, then Python can override the default behavior and call the descriptor instead. If this happens in the priority chain, it depends on which descriptor methods have been defined.

The purpose of __get__ is to control what happens once when the ax is through this "search chain" (for example, to create a method object instead of returning a simple function found through type(a).__dict__['x'] ); the purpose of __getattr__ and __getattribute__ is to change the search chain itself.

There is no __setattribute__ , because there is only one way to set the attribute of an object under the hood. You might want other events to happen β€œmagically” when the attribute was set; but __setattr__ covers that. __setattribute__ cannot provide any functions that __setattr__ does not yet exist.

However, the best answer in the vast majority of cases is to not even think about using any of them. First, consider higher-level abstractions such as property s, classmethod s, and staticmethod s. If you think that you need specialized tools like this, and you cannot understand it yourself, there are good chances that you are mistaken in your thinking; but independently, it is better to pose a more specific question in this case.

+6
source

Source: https://habr.com/ru/post/975192/


All Articles