Re: How to replace an instance method?

2022-09-17 Thread Eryk Sun
On 9/17/22, Chris Angelico  wrote:
>
> A method IS a function. A bound method is a function with one argument
> locked in, but still a function.

We were talking past each other. A method object is not a function
object. You're talking about a function defined in a class that's
accessed as a method of an instance of the class. In the class, that's
just a function object; it's exactly a function, not merely
fundamentally the same thing as one. It's only when accessed as an
attribute of an instance of the type that the function's descriptor
__get__() method is called to bind it and the instance to a method
object that sets the instance as its __self__ and the function as its
__func__.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Chris Angelico
On Sun, 18 Sept 2022 at 10:29,  wrote:
>
>
> From your description, Chris, it sounds like the functional programming
> technique often called currying. A factory function is created where one (or
> more) parameters are sort of frozen in so the user never sees or cares about
> them, and a modified or wrapped function is returned. In this case, the
> function now knows what object it is attached to as this.
>

Correct. I avoided the technical term but that is exactly what's happening.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


RE: How to replace an instance method?

2022-09-17 Thread avi.e.gross


>From your description, Chris, it sounds like the functional programming
technique often called currying. A factory function is created where one (or
more) parameters are sort of frozen in so the user never sees or cares about
them, and a modified or wrapped function is returned. In this case, the
function now knows what object it is attached to as this.

-Original Message-
From: Python-list  On
Behalf Of Chris Angelico
Sent: Saturday, September 17, 2022 8:21 PM
To: python-list@python.org
Subject: Re: How to replace an instance method?

On Sun, 18 Sept 2022 at 09:37, Eryk Sun  wrote:
>
> On 9/17/22, Chris Angelico  wrote:
> >
> > The two are basically equivalent. Using functools.partial emphasizes 
> > the fact that all you're doing is "locking in" the first parameter; 
> > using the __get__ method emphasizes the fact that functions are, 
> > fundamentally, the same thing as methods. Choose whichever one makes 
> > sense to you!
>
> Functions are really not "fundamentally, the same thing as methods".
> They're only the same in that they're both callable. Also, a method's
> __getattribute__() falls back on looking up attributes on the 
> underlying function (i.e. the method's __func__), such as inspecting 
> the __name__ and __code__. A fundamental difference is that, unlike a 
> function, a method is not a descriptor. Thus if a method object is set 
> as an attribute of a type, the method does not rebind as a new method 
> when accessed as an attribute of an instance of the type.

An unbound method in Python 2 was distinctly different from a function, but
in Python 3, they really truly are the same thing. A bound method object is
a small wrapper around a function which binds its 'self' parameter; that's a
distinction, but not a fundamental one.
Yes, a bound method isn't a descriptor; that's not really a huge difference
either, though.

A method IS a function. A bound method is a function with one argument
locked in, but still a function.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Chris Angelico
On Sun, 18 Sept 2022 at 09:37, Eryk Sun  wrote:
>
> On 9/17/22, Chris Angelico  wrote:
> >
> > The two are basically equivalent. Using functools.partial emphasizes
> > the fact that all you're doing is "locking in" the first parameter;
> > using the __get__ method emphasizes the fact that functions are,
> > fundamentally, the same thing as methods. Choose whichever one makes
> > sense to you!
>
> Functions are really not "fundamentally, the same thing as methods".
> They're only the same in that they're both callable. Also, a method's
> __getattribute__() falls back on looking up attributes on the
> underlying function (i.e. the method's __func__), such as inspecting
> the __name__ and __code__. A fundamental difference is that, unlike a
> function, a method is not a descriptor. Thus if a method object is set
> as an attribute of a type, the method does not rebind as a new method
> when accessed as an attribute of an instance of the type.

An unbound method in Python 2 was distinctly different from a
function, but in Python 3, they really truly are the same thing. A
bound method object is a small wrapper around a function which binds
its 'self' parameter; that's a distinction, but not a fundamental one.
Yes, a bound method isn't a descriptor; that's not really a huge
difference either, though.

A method IS a function. A bound method is a function with one argument
locked in, but still a function.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Eryk Sun
On 9/17/22, Chris Angelico  wrote:
>
> The two are basically equivalent. Using functools.partial emphasizes
> the fact that all you're doing is "locking in" the first parameter;
> using the __get__ method emphasizes the fact that functions are,
> fundamentally, the same thing as methods. Choose whichever one makes
> sense to you!

Functions are really not "fundamentally, the same thing as methods".
They're only the same in that they're both callable. Also, a method's
__getattribute__() falls back on looking up attributes on the
underlying function (i.e. the method's __func__), such as inspecting
the __name__ and __code__. A fundamental difference is that, unlike a
function, a method is not a descriptor. Thus if a method object is set
as an attribute of a type, the method does not rebind as a new method
when accessed as an attribute of an instance of the type.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Chris Angelico
On Sun, 18 Sept 2022 at 07:20, Ralf M.  wrote:
>
> Am 16.09.2022 um 23:34 schrieb Eryk Sun:
> > On 9/16/22, Ralf M.  wrote:
> >> I would like to replace a method of an instance, but don't know how to
> >> do it properly.
> >
> > A function is a descriptor that binds to any object as a method. For 
> > example:
> >
> >  >>> f = lambda self, x: self + x
> >  >>> o = 42
> >  >>> m = f.__get__(o)
> >  >>> type(m)
> >  
> >  >>> m.__self__ is o
> >  True
> >  >>> m(10)
> >  52
>
> Thank you and Chris A. for the two suggestions how to replace a method.
>
> I tried both
>inst.method = functools.partial(new_method, inst)
> and
>inst.method = new_method.__get__(inst)
> and both work in my toy example.
> I will try it on the real code next week.
>
> Even though the functools.partial solution is easier to understand (at
> least for me), I will probably use the __get__ solution as it avoids
> the import of an extra library.
>

The two are basically equivalent. Using functools.partial emphasizes
the fact that all you're doing is "locking in" the first parameter;
using the __get__ method emphasizes the fact that functions are,
fundamentally, the same thing as methods. Choose whichever one makes
sense to you!

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Ralf M.

Am 17.09.2022 um 00:35 schrieb Dan Stromberg:



On Fri, Sep 16, 2022 at 2:06 PM Ralf M. > wrote:


I would like to replace a method of an instance, but don't know how to
do it properly.


You appear to have a good answer, but...  are you sure this is a good idea?


It's definitely a dirty hack.

It'll probably be confusing to future maintainers of this code, and I 
doubt static analyzers will like it either.


I agree that I will have to add sufficient comments for the future
maintainer, should there ever be one (and even for me to still
understand it next year). I don't use static analyzers.

I'm not the biggest fan of inheritance you'll ever meet, but maybe this 
is a good place for it?


Using a derived version of the class in question to overwrite the
method was my first idea, however I don't instantiate the class in
question myself, it is instantiated during the initialisation of
another class, so I would at least have to derive a modified version of
that as well. And that code is rather complex, with metaclasses and
custom decorators, and I feel uncomfortable messing with that, while
the method I intend to change is quite simple and straightforward.

In case anybody is interested what I'm trying to achieve:

It's simple in pandas to read an excel file into a dataframe, but only
the cell value is read. Sometimes I need more / other information, e.g.
some formatting or the hyperlink in a cell. Reopening the file with
openpyxl and getting the info is possible, but cumbersome.
Looking into the pandas code for reading excel files (which uses
openpyxl internally) I noticed a method (of an internal pandas class)
that extracts the value from an openpyxl cell. This method is rather
simple and seems the ideal spot to change to get what I want.

My idea is to instantiate pandas.ExcelFile (official pandas API), get
the reader instance (an attribute of the ExcelFile object) and modify
the method of the reader instance.

The fact that the method I change and the ExcelFile attribute containing
the reader are both private (start with _) doesn't make it any better,
but I'm desperate enough to be willing to adapt my code to every major
pandas release, if necessary.

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list


Re: How to replace an instance method?

2022-09-17 Thread Ralf M.

Am 16.09.2022 um 23:34 schrieb Eryk Sun:

On 9/16/22, Ralf M.  wrote:

I would like to replace a method of an instance, but don't know how to
do it properly.


A function is a descriptor that binds to any object as a method. For example:

 >>> f = lambda self, x: self + x
 >>> o = 42
 >>> m = f.__get__(o)
 >>> type(m)
 
 >>> m.__self__ is o
 True
 >>> m(10)
 52


Thank you and Chris A. for the two suggestions how to replace a method.

I tried both
  inst.method = functools.partial(new_method, inst)
and
  inst.method = new_method.__get__(inst)
and both work in my toy example.
I will try it on the real code next week.

Even though the functools.partial solution is easier to understand (at
least for me), I will probably use the __get__ solution as it avoids
the import of an extra library.

Ralf M.
--
https://mail.python.org/mailman/listinfo/python-list