I would like to replace a method of an instance, but don't know how to
do it properly.
I would like to replace a method of an instance, but don't know how to
do it properly.
My first naive idea was
inst = SomeClass()
def new_method(self, param):
# do something
return whatever
inst.method = new_method
however that doesn't work: self isn't passed as first parameter to
the new inst.method, instead inst.method behaves like a static method.
I had a closer look at the decorators classmethod and staticmethod. Unfortunetely I couldn't find a decorator / function "instancemethod"
that turns a normal function into an instancemethod.
The classmethod documentation contains a reference to the standard
type hierarchie, and there is an explanation that an instancemethod
is sort of a dynamically created wrapper around a function, which
is accessable as __func__.
So I modified the last line of the example above to
inst.method.__func__ = new_method
but got told that __func__ is read only.
I found some information about methods in the Descriptor HowTo Guide,
but it's about how it works internally and doesn't tell how to solve
my problem (at least it doesn't tell me).
Now I'm running out of ideas what to try next or what sections of the documentation to read next.
Any ideas / pointers?
I would like to replace a method of an instance, but don't know how to
do it properly.
On Fri, Sep 16, 2022 at 2:06 PM Ralf M. <Ralf_M@t-online.de> 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'll probably be confusing to future maintainers of this code, and I doubt static analyzers will like it either.
I'm not the biggest fan of inheritance you'll ever meet, but maybe this is
a good place for it?
I would like to replace a method of an instance, but don't know how to
do it properly.
My first naive idea was
inst = SomeClass()
def new_method(self, param):
# do something
return whatever
inst.method = new_method
On 9/16/22, Ralf M. <Ralf_M@t-online.de> 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)
<class 'method'>
>>> m.__self__ is o
True
>>> m(10)
52
On Fri, Sep 16, 2022 at 2:06 PM Ralf M. <Ralf_M@t-online.de <mailto:Ralf_M@t-online.de>> 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'll probably be confusing to future maintainers of this code, and I
doubt static analyzers will like it either.
I'm not the biggest fan of inheritance you'll ever meet, but maybe this
is a good place for it?
Am 16.09.2022 um 23:34 schrieb Eryk Sun:
On 9/16/22, Ralf M. <Ralf_M@t-online.de> 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)
<class 'method'>
>>> 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!
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.
On 9/17/22, Chris Angelico <rosuav@gmail.com> 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.
On 9/17/22, Chris Angelico <rosuav@gmail.com> 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.
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.
A method IS a function. A bound method is a function with one argument
locked in, but still a function.
types.MethodType( function, instance )
functools.partial( function, instance )
new_method.__get__( instance )
We were talking past each other. A method object is not a function
object.
ram@zedat.fu-berlin.de (Stefan Ram) writes (abbreviated):
types.MethodType( function, instance )
functools.partial( function, instance )
new_method.__get__( instance )
I wonder which of these three possibilities expresses
the idea of creating a new method from a function and
an instance most clearly.
ram@zedat.fu-berlin.de (Stefan Ram) writes (abbreviated):
types.MethodType( function, instance )
functools.partial( function, instance )
new_method.__get__( instance )
I wonder which of these three possibilities expresses
the idea of creating a new method from a function and
an instance most clearly.
On 2022-09-18 at 09:11:28 +0000,
Stefan Ram <ram@zedat.fu-berlin.de> wrote:
ram@zedat.fu-berlin.de (Stefan Ram) writes (abbreviated):
types.MethodType( function, instance )
functools.partial( function, instance )
new_method.__get__( instance )
I wonder which of these three possibilities expresses
the idea of creating a new method from a function and
an instance most clearly.
The first one. And only the first one.
The second one requires too much inside knowledge of Python to make the
leap from currying to instance method.
The third one doesn't even mention the function.
From: "Weatherby,Gerard" <gweatherby@uchc.edu>
Date: Mon, 19 Sep 2022 13:06:42 +0000
Subject: Re: How to replace an instance method?
Just subclass and override whatever method you wish to modify
“Private” is conceptual. Mostly it means when the next version of a module comes out, code that you wrote that accesses *._ parts of the module might break.
___
import pandas
class MyClass(pandas.ExcelFile.OpenpyxlReader):
def _convert_cell(self, cell, convert_float: bool) -> 'Scalar':
"""override"""
# do whatever you want, or call the base class version
return super()._convert_cell(cell, convert_float)
—
Gerard Weatherby | Application Architect NMRbox | NAN | Department of Molecular Biology and Biophysics
UConn Health 263 Farmington Avenue, Farmington, CT 06030-6406 uch
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 300 |
Nodes: | 16 (2 / 14) |
Uptime: | 66:01:44 |
Calls: | 6,712 |
Files: | 12,244 |
Messages: | 5,356,309 |