importing a method

F

Flavio

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
 
B

Ben Finney

Flavio said:
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:
... pass
... ... print "bar() got arguments:", args
... 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.
 
C

Chris Curvey

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()
 
F

Flavio

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.
 
F

Flavio

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: name='John'
self=parent
print 'Hi, %s!'%self.name

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
 
F

Flavio

There only one puzzle left to solve:

altough the solution I proposed works, this variant has problems:
name='John'
NameError: global name 'self' is not defined

This error is paradoxical since:
<__main__.Foo instance at 0x405ed2ec>

Can anyone explain this?
 
A

Antoon Pardon

Op 2005-11-27 said:
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:
.... def __init__(self, v):
.... self.value = v
.... .... print self.value
.... 17
 
F

Flavio

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
 
F

Flavio

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.
 
A

Alex Martelli

Flavio said:
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
 
M

Martin Miller

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
 
M

Martin Miller

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
 
F

Flavio

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
 
F

Flavio

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
 
S

Steven D'Aprano

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.'
 
A

Alex Martelli

Martin Miller said:
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?

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
 
A

Alex Martelli

Flavio said:
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
 
M

Martin Miller

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]: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 said:
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 said:
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
 
M

Martin Miller

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:<__main__.old instance at 0x009D5F30>

So I stand corrected -- thank you.

Best,
-Martin

==============
 
A

Alex Martelli

Martin Miller said:
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:<__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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Problem with importing in Python 12
Method chaining 16
Importing by file name 1
Code sharing 2
Importing 2
Py file import stops importing 1
Importing class from another file 1
error importing modules 0

Members online

Forum statistics

Threads
474,273
Messages
2,571,363
Members
48,049
Latest member
DomenicMon

Latest Threads

Top