Question regarding unexpected behavior in using __enter__ method

Lorenzo Catoni l.catoni.99 at gmail.com
Fri Apr 21 03:46:00 EDT 2023


Thankyou for your answer,
i think i found the reason for this behavior, is has to do with the
function being user defined or not, rather than being a plain function or
type, as stated here
https://docs.python.org/3/reference/datamodel.html#:~:text=Also%20notice%20that%20this%20transformation%20only%20happens%20for%20user%2Ddefined%20functions%3B%20other%20callable%20objects%20(and%20all%20non%2Dcallable%20objects)%20are%20retrieved%20without%20transformation

Regards,
Lorenzo Catoni

On Fri, 21 Apr 2023 at 07:21, Cameron Simpson <cs at cskk.id.au> wrote:

> On 21Apr2023 00:44, Lorenzo Catoni <l.catoni.99 at gmail.com> wrote:
> >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.
>
> My descriptor fu is weak, but I believe this is because `int` is not a
> plain function but a type.
>
> Consider this class definition:
>
>      class X:
>         x = 1
>         def y(self):
>             return "y"
>
> When you define a class, the body of the class is run in a namespace,
> and on completion, the namespace is _used_ to construct the class.
> During that process, the various names are considered. Here we've got 2
> names: "x" and "y".
>
> "x" refers to an int and is just stored as a class attribute, unchanged.
>
> "y" refers to a function, and is promoted to a descriptor of an unbound
> method.
>
> So later: X.x return 1 but X.y returns a unbound method. If we make an
> instance:
>
>      objx = X()
>
> then obj.x returns 1 (by not fining an "x" on "obj", but finding one on
> "type(obj)" i.e. the class attribute.
>
> By contrast, obj.y returns a bound method, a function already curried
> with a leading parameter "obj" (which will be "self"). There's no "y"
> attribute directly on "obj" but there's an unbound method on
> "type(obj).y", which gets bound by saying "obj.y".
>
> The means that what happens to a name when you define the class depends
> on the typeof the value bound to the name.
>
> A plain function gets turned into an unbound instance method, but other
> things are left alone.
>
> When you went:
>
>      __enter__ = int
>
> That's not a plain function and so "obj.__enter__" doesn't turn into a
> bound method - it it just `int`.
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> --
> https://mail.python.org/mailman/listinfo/python-list
>


More information about the Python-list mailing list