467,146 Members | 1,242 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

Post your question to a community of 467,146 developers. It's quick & easy.

importing a method

hi,

I have an object defined with a number of hardcoded methods.

Class soandso:
def __init__(self):
self.this = 0
self.that = 1
def meth1(self):
...
def meth2(self):
...
def custom(self):
pass

I want to allow the user to write a python module that declares a
function so that myprogram can import it and attribute it to the custom
method of the soandso object. So far so good, that is an easy thing to
do in Python.

import usermodule
a=soandso()
a.custom = usermodule.function

But, what if the method had to access the self attributes (self.this
and self.that) of the soandso object?

Can it be done? and if so, what is the most Pythonic way of doing it?

thanks in advance,

Flávio

Nov 27 '05 #1
  • viewed: 1635
Share:
19 Replies
Flavio <fc******@gmail.com> wrote:
Class soandso:
def __init__(self):
self.this = 0
self.that = 1
def meth1(self):
...
def meth2(self):
...
def custom(self):
pass

I want to allow the user to write a python module that declares a
function so that myprogram can import it and attribute it to the custom
method of the soandso object. So far so good, that is an easy thing to
do in Python.

import usermodule
a=soandso()
a.custom = usermodule.function
Apparently you haven't tested whether this works. It doesn't:
class Foo(object): ... pass
... def bar(*args): ... print "bar() got arguments:", args
... bar("spam", "eggs") bar() got arguments: ('spam', 'eggs') Foo.bar_method = bar
Foo.bar_method("spam", "eggs") Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unbound method bar() must be called with Foo instance as first argument (got str instance instead)
But, what if the method had to access the self attributes (self.this
and self.that) of the soandso object?


To become a method, the function must be bound to an instance, and the
method will then receive the instance as the first argument when
called as a method.

To do this on an already-defined function, use new.instancemethod.
import new
help(new.instancemethod)


--
\ "One time a cop pulled me over for running a stop sign. He |
`\ said, 'Didn't you see the stop sign?' I said, 'Yeah, but I |
_o__) don't believe everything I read.'" -- Steven Wright |
Ben Finney
Nov 28 '05 #2
why not just have your user subclass "soandso" and override the
definition of "custom"?

from soandso import soandso
class MyClass(soandso):
def custom(self):
self.theother = 3

c = MyClass()

Nov 28 '05 #3
Because, by the time the user function is imported and attributed to
the custom method, soandso has already been instantiated and contains
the information tha needs to accessed by the user's function.

Nov 28 '05 #4
If you read my original post, I had no intention of atributing the
user's method to the class, but to the instance.

Anyway I figure it out myself, and its quite a Pythonic solution:
class Foo: name='John'
a=Foo() def p(parent): self=parent
print 'Hi, %s!'%self.name

a.met=p a.met(a)

Hi, John!

This works the same way an object's built-in method would work, since
all methods receive a reference to the parent object through the
required argument "self".

class Foo:
def met(self):
print self

Thanks for all the replies, they helped to catalize my own thoughts!

Flávio

Nov 28 '05 #5
There only one puzzle left to solve:

altough the solution I proposed works, this variant has problems:
class Foo: name='John'
a=Foo()
def p(): print 'Hi, %s!'%self.name a.met=p
a.met.self = a
a.met() NameError: global name 'self' is not defined

This error is paradoxical since:
a.met.self

<__main__.Foo instance at 0x405ed2ec>

Can anyone explain this?

Nov 28 '05 #6
Op 2005-11-27, Flavio schreef <fc******@gmail.com>:
hi,

I have an object defined with a number of hardcoded methods.

Class soandso:
def __init__(self):
self.this = 0
self.that = 1
def meth1(self):
...
def meth2(self):
...
def custom(self):
pass

I want to allow the user to write a python module that declares a
function so that myprogram can import it and attribute it to the custom
method of the soandso object. So far so good, that is an easy thing to
do in Python.

import usermodule
a=soandso()
a.custom = usermodule.function

But, what if the method had to access the self attributes (self.this
and self.that) of the soandso object?

Can it be done? and if so, what is the most Pythonic way of doing it?


You mean something like this:
class Foo: .... def __init__(self, v):
.... self.value = v
.... def show(self): .... print self.value
.... import new
f = Foo(17)
f.show = new.instancemethod(show, f)
f.show()

17

--
Antoon Pardon
Nov 28 '05 #7
This "new" module sounds pretty cool, too bad its deprecated...

I would not want to add a dependancy to a deprecated module in my code.
But maybe I'll check the code for instancemethod within it and see what
it does.

Flávio

Nov 28 '05 #8
Addendum to my last reply:

although the New Method is deprecated,

new.instancemethod (from Antoon's message) can be replaced by

from types import MethodType

f.show = MethodType(show,f)

and every thing still works.

Nov 28 '05 #9
Flavio <fc******@gmail.com> wrote:
This "new" module sounds pretty cool, too bad its deprecated...

I would not want to add a dependancy to a deprecated module in my code.
But maybe I'll check the code for instancemethod within it and see what
it does.


If you have a function f and want to make an instancemethod out of it,
you can simply call f.__get__(theinstance, theclass) and that will build
and return the new instancemethod you require.
Alex
Nov 28 '05 #10
First of all,why do you think the new module is deprecated? (I can't
find anything in the docs to indicate this.)

As for using MethodType in the types module: There's nothing in the
module documentation that suggests that you can call MethodType as a
function as you suggest, only that it is the name of the type of
methods of user-defined class instances.. So, while calling it might
work, it sounds like you are using an undocumented feature...

Lastly, in an earlier post after Ben Finney suggested using the
new.instancemethod function, you replied:
If you read my original post, I had no intention of atributing the
user's method to the class, but to the instance.
I'd like to point out that the instancemethod() function returns a
method object, bound to its *instance* argument if it isn't None --
which sounds like exactly what you want/need.

-Martin
Flavio wrote: Addendum to my last reply:

although the New Method is deprecated,

new.instancemethod (from Antoon's message) can be replaced by

from types import MethodType

f.show = MethodType(show,f)

and every thing still works.


Nov 28 '05 #11
I'd like to point out to the OP that using a function's __get__ method
this way only works with new-style classes and their instances...not
with the example in the shown in original post.

-Martin
Alex Martelli wrote:
Flavio <fc******@gmail.com> wrote:
This "new" module sounds pretty cool, too bad its deprecated...

I would not want to add a dependancy to a deprecated module in my code.
But maybe I'll check the code for instancemethod within it and see what
it does.


If you have a function f and want to make an instancemethod out of it,
you can simply call f.__get__(theinstance, theclass) and that will build
and return the new instancemethod you require.
Alex


Nov 28 '05 #12
> First of all,why do you think the new module is deprecated? (I can't
find anything in the docs to indicate this.)
Its in the docs of python 2.4. I dont know about older versions:

Help on module new:

NAME
new - Create new objects of various types. Deprecated.

FILE
/usr/lib/python2.4/new.py

MODULE DOCS
/usr/share/doc/python-docs-2.4.2/html/module-new.html

DESCRIPTION
This module is no longer required except for backward
compatibility.
Objects of most types can now be created by calling the type
object.
As for using MethodType in the types module: There's nothing in the
module documentation that suggests that you can call MethodType as a
function as you suggest, only that it is the name of the type of
methods of user-defined class instances.. So, while calling it might
work, it sounds like you are using an undocumented feature...


If you look at new.py, all it does is import the functions from types
and rename them. For MethodType is goes like this

from types import MethodType as instancemethod

so instance method *is* Methodtype.

Moreover, I tried and it works ;-)

So this solution is perfect once adapted not to depend on "new".

Thanks,

Flávio

Nov 28 '05 #13
> If you have a function f and want to make an instancemethod out of it,
you can simply call f.__get__(theinstance, theclass) and that will build
and return the new instancemethod you require.


I think that

f.show = MethodType(show,f)

is less cryptic than f.__get__(instance, class)

Flávio

Nov 28 '05 #14
On Mon, 28 Nov 2005 08:16:12 -0800, Martin Miller wrote:
First of all,why do you think the new module is deprecated? (I can't
find anything in the docs to indicate this.)


Did you try help(new) from an interactive prompt?
py> new.__doc__.splitlines()[0]
'Create new objects of various types. Deprecated.'
--
Steven.

Nov 28 '05 #15
Martin Miller <gg****************@dfgh.net> wrote:
I'd like to point out to the OP that using a function's __get__ method
this way only works with new-style classes and their instances...not
with the example in the shown in original post.


Uh, why not?
class old: pass .... def f(self): print self .... o=old()
o.z = f.__get__(o, old)
o.z <bound method old.f of <__main__.old instance at 0x53d78>>


There's a million reason to avoid using old-style classes in new code,
but it doesn't seem to me that this is one of them. What am I missing?
Alex
Nov 29 '05 #16
Flavio <fc******@gmail.com> wrote:
If you have a function f and want to make an instancemethod out of it,
you can simply call f.__get__(theinstance, theclass) and that will build
and return the new instancemethod you require.


I think that

f.show = MethodType(show,f)

is less cryptic than f.__get__(instance, class)


Hmmm, we're using different identifiers here for the same purposes,
making direct comparisons difficult. Using clear identifiers in every
case, and avoiding keywords, we'd have something like:

from types import MethodType
instance.show = MethodType(show, instance, aclass)

versus

instance.show = show.__get__(instance, aclass)

[[you do need to pass the class if you want the repr of instance.show to
look nice, and this applies equally to both cases]].

I guess that instantiating a type (here, instancemethod) by calling it
with appropriate arguments is the "normal" approach, and calling
MethodType has the further advantage of working with different types as
the callable (first argument), not just functions. The advantage of
__get__ is only polymorphism on different descriptor types, but that
looks rather less important. So, "cryptic" apart (an issue on which one
could debate endlessly -- I'd argue that descriptors should be well
familiar by the time one starts generating methods on the fly;-),
calling MethodType does cover a wider range of uses.
Alex
Nov 29 '05 #17
Sorry, I seldom look at the built-in __doc__ strings or use the
'help()' function. Instead I usually refer to the html or winhelp
versions of the documentation, and for Python 2.4.1 there's nothing in
section 3.28 on the 'new' module that mentions that it deprecated -- so
thanks to you and Flávio for the information.

Using help on MethodType gave me the following somewhat surprising
output [truncated here]:
import types
help(types.MethodType)
Help on class instancemethod in module __builtin__:

class instancemethod(object)
| instancemethod(function, instance, class)
|
| Create an instance method object.
[snip]

Which I take to mean that 'instancemethod' is no longer [just] a
function in the deprecated 'new' module but is also a built-in class.

However and somewhat confusingly (to me anyway), a search in the help
docs file turns up the following:
7.5.3 Method Objects
There are some useful functions that are useful for working with method objects.

PyTypeObject PyMethod_Type
This instance of PyTypeObject represents the Python method type. This is
exposed to Python programs as types.MethodType.
... [snip]

Which, as you can see, claims that types.MethodType is actually an
instance of a PyTypeObject (not the class instancemethod that
help(types.MethodType) indicated).

Best,
-Martin

====
Steven D'Aprano wrote: On Mon, 28 Nov 2005 08:16:12 -0800, Martin Miller wrote:
First of all,why do you think the new module is deprecated? (I can't
find anything in the docs to indicate this.)


Did you try help(new) from an interactive prompt?
py> new.__doc__.splitlines()[0]
'Create new objects of various types. Deprecated.'
--
Steven.

Flávio wrote: First of all,why do you think the new module is deprecated? (I can't
find anything in the docs to indicate this.)


Its in the docs of python 2.4. I dont know about older versions:

Help on module new:

NAME
new - Create new objects of various types. Deprecated.

FILE
/usr/lib/python2.4/new.py

MODULE DOCS
/usr/share/doc/python-docs-2.4.2/html/module-new.html

DESCRIPTION
This module is no longer required except for backward
compatibility.
Objects of most types can now be created by calling the type
object.
As for using MethodType in the types module: There's nothing in the
module documentation that suggests that you can call MethodType as a
function as you suggest, only that it is the name of the type of
methods of user-defined class instances.. So, while calling it might
work, it sounds like you are using an undocumented feature...


If you look at new.py, all it does is import the functions from types
and rename them. For MethodType is goes like this

from types import MethodType as instancemethod

so instance method *is* Methodtype.

Moreover, I tried and it works ;-)

So this solution is perfect once adapted not to depend on "new".

Thanks,

Flávio


Dec 1 '05 #18
You're not missing anything -- it's my own [mis-]understanding that
descriptors would only work with new-style classes, not the old-style
ones used in the OP's example.

However your example certainly proves that is not the case, even if you
go one step further and call the bound method/function:
o.z()
<__main__.old instance at 0x009D5F30>

So I stand corrected -- thank you.

Best,
-Martin

==============
Alex Martelli wrote:
Martin Miller <gg****************@dfgh.net> wrote:
I'd like to point out to the OP that using a function's __get__ method
this way only works with new-style classes and their instances...not
with the example in the shown in original post.


Uh, why not?
class old: pass ... def f(self): print self ... o=old()
o.z = f.__get__(o, old)
o.z <bound method old.f of <__main__.old instance at 0x53d78>>


There's a million reason to avoid using old-style classes in new code,
but it doesn't seem to me that this is one of them. What am I missing?
Alex


Dec 1 '05 #19
Martin Miller <gg****************@dfgh.net> wrote:
You're not missing anything -- it's my own [mis-]understanding that
descriptors would only work with new-style classes, not the old-style
ones used in the OP's example.

However your example certainly proves that is not the case, even if you
go one step further and call the bound method/function:
o.z()

<__main__.old instance at 0x009D5F30>

So I stand corrected -- thank you.


You're welcome. Your previous misunderstanding may be due to the fact
that (differently from __get__) the special method __set__ doesn't work
when the descriptor is held in an old-style class... to be more precise,
it's not even given a chance, since assigning to an instance attribute
(where the instance's old-style) just blithely sets the value in the
instance's __dict__, without even checking for the existence of a
descriptor by that name in the class.
Alex
Dec 1 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

11 posts views Thread by Jeff Wagner | last post: by
2 posts views Thread by Awah Teh | last post: by
4 posts views Thread by Little PussyCat | last post: by
7 posts views Thread by Timothy Shih | last post: by
reply views Thread by Ivan Lam | last post: by
3 posts views Thread by martin | last post: by
2 posts views Thread by HMS Surprise | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.