Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

To err is human, to moo bovine.


devel / comp.lang.python / getting rid of the recursion in __getattribute__

SubjectAuthor
* getting rid of the recursion in __getattribute__A KR
`- Re: getting rid of the recursion in __getattribute__Peter Otten

1
getting rid of the recursion in __getattribute__

<528e330c-52b3-4552-b7d3-15b69b1d6c9bn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=27791&group=comp.lang.python#27791

  copy link   Newsgroups: comp.lang.python
X-Received: by 2002:a05:6214:b2a:b0:625:aa1a:b043 with SMTP id w10-20020a0562140b2a00b00625aa1ab043mr253697qvj.13.1684935451871;
Wed, 24 May 2023 06:37:31 -0700 (PDT)
X-Received: by 2002:a05:6820:16a6:b0:547:150a:fd1a with SMTP id
bc38-20020a05682016a600b00547150afd1amr7332802oob.0.1684935451354; Wed, 24
May 2023 06:37:31 -0700 (PDT)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!panix!1.us.feeder.erje.net!feeder.erje.net!border-1.nntp.ord.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.python
Date: Wed, 24 May 2023 06:37:31 -0700 (PDT)
Injection-Info: google-groups.googlegroups.com; posting-host=37.228.255.234; posting-account=EPMnWQoAAADYjt3TM1ZfDvNdJ7DlrumQ
NNTP-Posting-Host: 37.228.255.234
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <528e330c-52b3-4552-b7d3-15b69b1d6c9bn@googlegroups.com>
Subject: getting rid of the recursion in __getattribute__
From: alicpp@gmail.com (A KR)
Injection-Date: Wed, 24 May 2023 13:37:31 +0000
Content-Type: text/plain; charset="UTF-8"
Lines: 83
 by: A KR - Wed, 24 May 2023 13:37 UTC

It is perfectly explained in the standards here [1] saying that:

<quote>
In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).
</quote>

Therefore, I wrote a code following what the standard says:

<code>
class Sample():
def __init__(self):
self.a = -10

def __getattribute__(self, name):
if name == 'a':
return object.__getattribute__(self, name)

raise AttributeError()

s = Sample()
result = s.a
print(result)
</code>
I did not fall into recursion, and the output was
-10

I used here object.__getattribute__(self, name) cause the base class of Sample is object.

If I derive the Sample class from another class such as A, I should change object.__getattribute__(self, name) to A.__getattribute__(self, name) as the base class of class Sample is class A.

<code>
class A:
pass

class Sample(A):
def __init__(self):
self.a = -10

def __getattribute__(self, name):
if name == 'a':
return A.__getattribute__(self, name)

raise AttributeError()

s = Sample()

result = s.a
print(result)
</code>
which gives the same output as expected. No recursion and -10.

However, when I try the code without deriving from a class:

class AnyClassNoRelation:
pass

class Sample():
def __init__(self):
self.a = -10

def __getattribute__(self, name):
if name == 'a':
return AnyClassNoRelation.__getattribute__(self, name)

raise AttributeError()

s = Sample()

result = s.a
print(result)
and calling __getattribute__ via any class (in this example class AnyClassNoRelation) instead of object.__getattribute__(self, name) as the standard says call using the base class, I get the same output: no recursion and -10.

So my question:

How come this is possible (having the same output without using the base class's __getattribute__? Although the standards clearly states that __getattribute__ should be called from the base class.

<quote>
In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).
</quote>

Literally, I can call __getattribute__ with anyclass (except Sample cause it will be infinite recursion) I define and it works just fine. Could you explain me why that happens?

[1] https://docs.python.org/3/reference/datamodel.html#object.__getattribute__

Re: getting rid of the recursion in __getattribute__

<mailman.0.1685001545.23016.python-list@python.org>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=27804&group=comp.lang.python#27804

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: __peter__@web.de (Peter Otten)
Newsgroups: comp.lang.python
Subject: Re: getting rid of the recursion in __getattribute__
Date: Thu, 25 May 2023 09:59:03 +0200
Lines: 132
Message-ID: <mailman.0.1685001545.23016.python-list@python.org>
References: <528e330c-52b3-4552-b7d3-15b69b1d6c9bn@googlegroups.com>
<b0bbc088-0c48-7803-efd9-5d4254d707ac@web.de>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Trace: news.uni-berlin.de EHj71Cy6KOmM6y0gC1zsVA+PDawhh/Iu0QZ1PVPCpZ+w==
Return-Path: <__peter__@web.de>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=web.de header.i=__peter__@web.de header.b=b8HyZ03D;
dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.005
X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'def': 0.04; 'traceback':
0.04; '(most': 0.05; 'class,': 0.05; 'last):': 0.05; 'class.':
0.07; 'explicitly': 0.07; 'received:212.227': 0.07; 'infinite':
0.09; 'output:': 0.09; 'question:': 0.09; 'skip:_ 20': 0.09;
'treated': 0.09; '(except': 0.16; 'arguments': 0.16; 'attributes':
0.16; 'from:addr:web.de': 0.16; 'message-id:@web.de': 0.16;
'received:mout.web.de': 0.16; 'received:web.de': 0.16;
'recursion': 0.16; 'recursion,': 0.16; 'says:': 0.16; 'tree,':
0.16; 'wrote:': 0.16; 'says': 0.17; 'instead': 0.17; 'to:addr
:python-list': 0.20; 'skip:_ 10': 0.22; 'code': 0.23;
'received:de': 0.23; "i'd": 0.24; 'saying': 0.25; 'object': 0.26;
'>>>': 0.28; 'output': 0.28; 'purpose': 0.28; 'example,': 0.28;
'header:User-Agent:1': 0.30; 'raise': 0.31; '"",': 0.32; 'fine.':
0.32; 'but': 0.32; 'there': 0.33; 'same': 0.34; 'header:In-Reply-
To:1': 0.34; 'following': 0.35; 'missing': 0.37; 'special': 0.37;
'using': 0.37; "it's": 0.37; 'class': 0.37; 'received:192.168':
0.37; 'file': 0.38; 'way': 0.38; 'could': 0.38; 'use': 0.39;
'wrote': 0.39; 'base': 0.40; 'define': 0.40; 'explain': 0.40;
'try': 0.40; 'should': 0.40; 'method': 0.61; 'sample': 0.61;
'received:212': 0.62; 'here': 0.62; 'come': 0.62; 'skip:o 20':
0.63; 'true': 0.63; 'pass': 0.64; 'explained': 0.64; 'imagine':
0.64; 'your': 0.64; '[1]': 0.67; 'order': 0.69; 'perfectly': 0.69;
'standards': 0.69; 'skip:a 40': 0.70; 'treat': 0.76; 'states':
0.80; 'attribute': 0.84; 'inheritance': 0.84; 'method,': 0.84;
'skip:" 40': 0.84; 'that:': 0.91; 'fall': 0.95
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=web.de; s=s29768273;
t=1685001543; i=__peter__@web.de;
bh=bdjelKFnpftX5dxPb642f06c2PF4WiVrCGuDQpDh7po=;
h=X-UI-Sender-Class:Date:Subject:To:References:From:In-Reply-To;
b=b8HyZ03Dr6Jv41BAOIJ7JvR23tBYkXnZMAEVf7hkGGmqZ13+1cBXMXrQFqx/qvHzJ
52PQHIlY563SF5P4oA090I230yL6JM2e74IiQF4TV2pif7mBPMBtZUTqBBKBlC7mIr
MpDEDdwR19oZxq6fu2so/Eu6CNVN6ElOZXZMqOyehh32Y8i4NIuwuB71BqOtTcdnAV
UacG7P7XYQSIuemV4wL+ctbevAMcRx6zQVXldByaMtuRFTPPyI1GlPMG2+9gn/L4kc
+LKU2w6VsvvJ0I1lG0x+Jgjv/8dQka39hcDtdU3zI6hOIRt+mQMQN+mAIML5ZjT4cY
hR9f5PidUksvA==
X-UI-Sender-Class: 814a7b36-bfc1-4dae-8640-3722d8ec6cd6
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101
Thunderbird/102.11.0
Content-Language: en-US
In-Reply-To: <528e330c-52b3-4552-b7d3-15b69b1d6c9bn@googlegroups.com>
X-Provags-ID: V03:K1:xvK0kZ9OnLMCfBoQtJX7bv2POfnszp2TJd53atmJn79QToKP7uB
/cvTa6XuS2kz+BLJkXvJlVwpJeuh/vaIuL5CqSVYAMFVKukcoCH7bhBAEYN9gZox+94kQ/O
eCBHkT+r+ca4jzIoWW/jmptCML9UIincPnNBa5sKhLXRL8aPq433K+gIvIiIpFBek+aBdpd
NiWHCXjlKpZTR4F8HgeZg==
X-Spam-Flag: NO
UI-OutboundReport: notjunk:1;M01:P0:Iu69CBdTBZU=;Hu/ifaapChoaEFrWZW9vvoLIcdt
5ce5bn3gzm6KYYyecMP4dCCGjLQPG4o7idC079nfUGmC/YKdveUt/mapuDjdxeplWVRMCcxQy
aQap+hYe5dYcHW4nUrZ9TeYkgBvHXlPQFJRgddH9nxv6oNuolibkKgwyhTy6OgZlQ9XRQ9zO3
igmzUJjGc+NnXL6tbPd6NbQhCzU7In5dCvPYHoCWm31ArGYqUbmcFd1/xpk948q8flHzvIqCj
ysvwgOYeSWoxkrc71iGeu9LCFbOIot8y2dtYH9GnyyIfZFvFlZHNEn5Ahs1aMgU7Hy0gmJWjr
6jxuuUBjgs1o465eh5czXNx+ZFp/fJ4LdohTMPOiBgHX092oOPxH+m+Uu805AFVpx+VpL9GKO
ILRH48XZPpQlO5C0g6IepUe4P+mGSbyAJiIs4WG+BawvqiMmeYmUHpsQQnT40U0FdUkopdXRw
joulITcNxXvfpnu9T/TO1W4qGyg3sMLiHAsm3NdWZgXs8AZ/S4o3oEc0r+sb1854wSB0Khi/f
mwonUMYhuYHxecu41+eVKoFYpPk0eDJk/tuQiEAiOdDptggz3BasMbLSJApHonAPnpdF7MyjA
kPydTbn59B1YFJ91YMKOgOSB/ZLmZ2sHigDHRhBvQ2Mek5e/1jVB7gzLcl8QqnsdOP8aNaqus
NTvPsZx/bYC/2qMB7w8YmFTL5ff8Ofk5MIwZaG5uejZ6iDHPNuj4YRtWUmjXN9SJKS7OVjblb
DLgR6bHJgLi7hUB2GhSpvi1urd1PHx9EF+f7GIZvxvap84LHkdDMZWpE2cWnM5ZltebgE5k0g
+yr1CjvC8Hgfp7zKdHA1C4bvFMESZZbUnsekYO7Wp5/GDknqomshT+v8bQKngEzWzn8l6QoaF
0P5AQlbtzzRXn5jj2kXsandjrm6GmDnlf7La/Jz0WDVS+N0+eKX/RCd5ar46OSFo5SlzVlrg0
4AjC6w==
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <b0bbc088-0c48-7803-efd9-5d4254d707ac@web.de>
X-Mailman-Original-References: <528e330c-52b3-4552-b7d3-15b69b1d6c9bn@googlegroups.com>
 by: Peter Otten - Thu, 25 May 2023 07:59 UTC

On 24/05/2023 15:37, A KR wrote:
> It is perfectly explained in the standards here [1] saying that:
>
> <quote>
> In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).
> </quote>
>
> Therefore, I wrote a code following what the standard says:
>
> <code>
> class Sample():
> def __init__(self):
> self.a = -10
>
> def __getattribute__(self, name):
> if name == 'a':
> return object.__getattribute__(self, name)
>
> raise AttributeError()
>
> s = Sample()
> result = s.a
> print(result)
> </code>
> I did not fall into recursion, and the output was
> -10

While this works it's not how I understand the recommended pattern. I'd
rather treat "special" attributes first and then use the
__getattribute__ method of the base class as a fallback:

>> class Demo:
def __getattribute__(self, name):
if name == "answer":
return 42
return super().__getattribute__(name)

That way your special arguments,

>>> d = Demo()
>>> d.answer
42

missing arguments

>>> d.whatever
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
d.whatever
File "<pyshell#10>", line 5, in __getattribute__
return super().__getattribute__(name)
AttributeError: 'Demo' object has no attribute 'whatever'

and "normal" arguments are treated as expected

>>> d.question = "What's up?"
>>> d.question
"What's up?"

Eventual "special" arguments in the superclass would also remain accessible.

> However, when I try the code without deriving from a class:
>
> class AnyClassNoRelation:
> pass
>
> class Sample():
> def __init__(self):
> self.a = -10
>
> def __getattribute__(self, name):
> if name == 'a':
> return AnyClassNoRelation.__getattribute__(self, name)
>
> raise AttributeError()
>
> s = Sample()
>
> result = s.a
> print(result)
> and calling __getattribute__ via any class (in this example class AnyClassNoRelation) instead of object.__getattribute__(self, name) as the standard says call using the base class, I get the same output: no recursion and -10.
>
> So my question:
>
> How come this is possible (having the same output without using the base class's __getattribute__? Although the standards clearly states that __getattribute__ should be called from the base class.

AnyClassNoRelation does not override __getattribute__, so

>>> AnyClassNoRelation.__getattribute__ is object.__getattribute__
True

There is no sanity check whether a method that you call explicitly is
actually in an object's inheritance tree,

>>> class NoRelation:
def __getattribute__(self, name):
return name.upper()

>>> class Demo:
def __getattribute__(self, name):
return "<{}>".format(NoRelation.__getattribute__(self, name))

>>> Demo().some_arg
'<SOME_ARG>'

but the only purpose I can imagine of actually calling "someone else's"
method is to confuse the reader...
> <quote>
> In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).
> </quote>
>
> Literally, I can call __getattribute__ with anyclass (except Sample cause it will be infinite recursion) I define and it works just fine. Could you explain me why that happens?


devel / comp.lang.python / getting rid of the recursion in __getattribute__

1
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor