1

Python has these methods: __getattr__, __getattribute__, and __setattr__. I know the difference between __getattr__ and __getattribute__, this thread explains it well. But I couldn't find anywhere anybody mentioning why __setattribute__ doesn't exist.

Does somebody know the reasons for this? Thank you.

acmpo6ou
  • 840
  • 1
  • 12
  • 21
  • https://docs.python.org/3/reference/datamodel.html?highlight=__setattr__#object.__setattr__ – 9769953 Apr 08 '23 at 09:09
  • @9769953 Yes, I checked the docs, but they don't mention `__setattribute__` at all. – acmpo6ou Apr 08 '23 at 09:11
  • Please see my original answer on the linked duplicate - your question was hinted at in passing in a comment in OP's code, and I addressed it. – Karl Knechtel Apr 08 '23 at 14:04
  • @KarlKnechtel Thanks. Weird that Google couldn't find your thread, I was using this query: `python "__setattribute__" site:stackoverflow.com`, which specifically says find me a web page containing exactly `"__setattribute__"`, belonging to stackoverflow.com domain. – acmpo6ou Apr 08 '23 at 15:27

1 Answers1

2

When getting an attribute, you can easily differentiate two cases: "this attribute exists in the normal path of attribute resolving" and "it can't be resolved via that path.". Therefore, there are two functions that can be plugged in: One that replaces the normal path (__getattribute__) and one that only handles the second case (__getattr__)

In contrast, since you can in general [1] assign arbitrary attributes to objects, it is not possible to make the distinction between "this attribute can be assigned normally" and "this attribute needs special handling". Therefore for setting an arbitrary attribute it wouldn't really make sense to have two functions since their functionality would be confusing at best and inconsistent[2] at worst. So you only get one that fully replaces the normal path (__setattr__).


[1] Usage of __slots__ and descriptors messes with this assumption. However, their usecases rarely overlap with the few situations where you would want to override attribute setting in general.

[2] The question is "when does __setattribute__" call out to __setattr__?" If it fails to set the attribute? If the attribute does not exists right now? If __getattribute__ would call __getattr__ when getting the attribute?

MegaIng
  • 7,361
  • 1
  • 22
  • 35
  • 1
    OK, thanks for your answer. What you're trying to say is: because it's possible to set any attribute on any instance, it doesn't matter whether the attribute exists or not? – acmpo6ou Apr 08 '23 at 09:16
  • 1
    @acmpo6ou To some extend yes (I just reworded my answer). The point is that `setattr` doesn't ever check if the attribute exists. (ok, it somewhat does because of descriptors, but that isn't the point) – MegaIng Apr 08 '23 at 09:20
  • @Megalng OK, it got a bit confusing. I now about slots, and I understand that generally you can set an arbitrary attribute on any class. But anyway, I understand the main point, so thank you. – acmpo6ou Apr 08 '23 at 10:21
  • 1
    Put another way: when setting an attribute, there is no *need* to check whether it exists, because either you are a) always allowed (normal cases) b) never allowed (built-in types that don't implement a proper attribute dictionary) c) conditionally allowed (based on `__slots__`); but in each of these cases it *doesn't matter* whether it already exists (even for the `__slots__` case, the attributes named by `__slots__` might not exist yet, but setting attributes that do and don't exist *works the same way*). – Karl Knechtel Apr 08 '23 at 14:07
  • @KarlKnechtel The one interesting exception you haven't mentioned is custom descriptors messing with you to confuse you. But that is very much a pathological edge case. – MegaIng Apr 08 '23 at 16:16