Question regarding unexpected behavior in using __enter__ method
Peter Otten
__peter__ at web.de
Fri Apr 21 03:41:07 EDT 2023
On 21/04/2023 00:44, Lorenzo Catoni wrote:
> Dear Python Mailing List members,
>
> I am writing to seek your assistance in understanding an unexpected
> behavior that I encountered while using the __enter__ method. I have
> provided a code snippet below to illustrate the problem:
>
> ```
>>>> class X:
> ... __enter__ = int
> ... __exit__ = lambda *_: None
> ...
>>>> with X() as x:
> ... pass
> ...
>>>> x
> 0
> ```
> As you can see, the __enter__ method does not throw any exceptions and
> returns the output of "int()" correctly. However, one would normally expect
> the input parameter "self" to be passed to the function.
>
> On the other hand, when I implemented a custom function in place of the
> __enter__ method, I encountered the following TypeError:
>
> ```
>>>> def myint(*a, **kw):
> ... return int(*a, **kw)
> ...
>>>> class X:
> ... __enter__ = myint
> ... __exit__ = lambda *_: None
> ...
>>>> with X() as x:
> ... pass
> ...
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "<stdin>", line 2, in myint
> TypeError: int() argument must be a string, a bytes-like object or a real
> number, not 'X'
> ```
> Here, the TypeError occurred because "self" was passed as an input
> parameter to "myint". Can someone explain why this unexpected behavior
> occurs only in the latter case?
Cameron is right, it's the descriptor protocol. Technically
inst.attr
invokes attr.__get__(...) if it exists:
>>> class A:
def __get__(self, *args): return args
>>> class B: pass
>>> class X:
a = A()
b = B()
>>> x = X()
>>> x.b
<__main__.B object at 0x02C2E388>
>>> x.a
(<__main__.X object at 0x02C2E280>, <class '__main__.X'>)
Python functions support the descriptor protocol
>>> hasattr(lambda: None, "__get__")
True
while builtin functions don't:
>>> hasattr(ord, "__get__")
False
I'm unsure whether to regard int as a class or or function, but as there
is no __get__
>>> hasattr(int, "__get__")
False
it behaves like builtin functions in this case.
More information about the Python-list
mailing list