How to get a reference of the 'owner' class to which a method belongsin Python 3.X?

C

Cosmia Luna

I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do nothing
pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

Thanks,
Cosmia
 
C

Chris Rebert

I'm porting my existing work to Python 3.X, but...

class Foo:
   def bar(self):
       pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators,

Could you give an example of such a decorator?

Cheers,
Chris
 
R

Richard Thomas

I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

mthd.im_class is the class of mthd.im_self not the class that defined the method.
So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

Not sure what sort of decorators you're writing. Examples?

You can achieve this with metaclasses but if you're using classes from someone else's code this doesn't necessarily work. Something in inspect module can probably do the trick, check the docs. Frankly though it sounds messy no matter what. It might be better to find an alternative to knowing the class.
class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do nothing
pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

Thanks,
Cosmia
 
C

Cosmia Luna

mthd.im_class is the class of mthd.im_self not the class that defined themethod.


Not sure what sort of decorators you're writing. Examples?

A decorator is not necessary but a similar function accept a method. I don't
like any of existing web frameworks and try to write one via werkzeug from
pocoo.

from myapp.controllers import RootController
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from werkzeug.wrappers import Request

url_map = Map([
Rule('/', endpoint=RootController.index),
Rule('/about', endpoint=RootController.about),
Rule('/contact', endpoint=RootController.contact),
Rule('/<action>/', endpoint=RootController.otheraction)
])

def application(environ, start_response): #this is a WSGI 1.0 app
bound_url_map = url_map.bind_to_environ(environ)
try:
endpoint, args = bound_url_map.match()
except HTTPException, e:
return e(environ, start_response)
Controller = endpoint.im_class
controller = Controller(Request(environ))
if hasattr(controller, '__before__'):
controller.__before__()
endpoint(controller)
if hasattr(controller, '__after__'):
controller.__after__()
response = controller.__get_response__():
return response(environ, start_response)

This is a Pylons-style application, but I don't like others in Pylons.
You can achieve this with metaclasses but if you're using classes from someone else's code this doesn't necessarily work. Something in inspect module can probably do the trick, check the docs. Frankly though it sounds messyno matter what. It might be better to find an alternative to knowing the class.
class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do nothing
pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

Thanks,
Cosmia
 
P

Peter Otten

Cosmia said:
I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do
nothing pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

class set_class:
def __init__(self, method):
self.method = method
def __get__(self, instance, class_):
if instance is None:
method = self.method
def f(*args, **kw):
return method(*args, **kw)
f.im_class = class_
f.__name__ = method.__name__
return f
return self.method.__get__(instance, class_)

class Foo:
def __init__(self, name):
self.name = name
@set_class
def bar(self):
print("%s says hello from bar()" % self)
def __str__(self):
return self.name

class Bar(Foo):
pass

assert Foo.bar.im_class is Foo
assert Bar.bar.im_class is Bar

Foo("Fred").bar()
Foo.bar(Foo("Fred"))

Bar("Fred").bar()
Bar.bar(Bar("Fred"))

The cleaner approach is probably:

Rule('/<action>/', endpoint=(RootController, RootController.otheraction))
....
Controller, method = endpoint
controller = Controller(Request(environ))
....
method(controller)
 
S

Steven D'Aprano

I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

I don't believe you can get a reference to Foo just by inspecting the
function object Foo.bar. (In Python 2.x, Foo.bar would be an unbound
method, but they no longer exist in Python 3.x.)

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

A better approach might be to inject a reference to the class after the
event, using a class decorator:

function = type(lambda: None)

def inject_class(cls):
for name, obj in vars(cls).items():
if type(obj) is function:
obj.owner_class = cls
return cls


And in use:

py> @inject_class
.... class Test:
.... a = 1
.... b = 2
.... def method(self, x):
.... return (x, self)
....
py> Test.a
1
py> Test.method
<function method at 0xb7b21bec>
py> Test.method.owner_class is Test
True


Does this help?
 
C

Cosmia Luna

Cosmia said:
I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do
nothing pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

class set_class:
def __init__(self, method):
self.method = method
def __get__(self, instance, class_):
if instance is None:
method = self.method
def f(*args, **kw):
return method(*args, **kw)
f.im_class = class_
f.__name__ = method.__name__
return f
return self.method.__get__(instance, class_)

class Foo:
def __init__(self, name):
self.name = name
@set_class
def bar(self):
print("%s says hello from bar()" % self)
def __str__(self):
return self.name

class Bar(Foo):
pass

assert Foo.bar.im_class is Foo
assert Bar.bar.im_class is Bar

Foo("Fred").bar()
Foo.bar(Foo("Fred"))

Bar("Fred").bar()
Bar.bar(Bar("Fred"))

The cleaner approach is probably:

Rule('/<action>/', endpoint=(RootController, RootController.otheraction))
...
Controller, method = endpoint
controller = Controller(Request(environ))
...
method(controller)


That's exactly what I want, and I think you're right, the approach below is cleaner.
Rule('/<action>/', endpoint=(RootController, RootController.otheraction)).

Thanks a lot.
Cosmia
 
C

Cosmia Luna

Cosmia said:
I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do
nothing pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

class set_class:
def __init__(self, method):
self.method = method
def __get__(self, instance, class_):
if instance is None:
method = self.method
def f(*args, **kw):
return method(*args, **kw)
f.im_class = class_
f.__name__ = method.__name__
return f
return self.method.__get__(instance, class_)

class Foo:
def __init__(self, name):
self.name = name
@set_class
def bar(self):
print("%s says hello from bar()" % self)
def __str__(self):
return self.name

class Bar(Foo):
pass

assert Foo.bar.im_class is Foo
assert Bar.bar.im_class is Bar

Foo("Fred").bar()
Foo.bar(Foo("Fred"))

Bar("Fred").bar()
Bar.bar(Bar("Fred"))

The cleaner approach is probably:

Rule('/<action>/', endpoint=(RootController, RootController.otheraction))
...
Controller, method = endpoint
controller = Controller(Request(environ))
...
method(controller)


That's exactly what I want, and I think you're right, the approach below is cleaner.
Rule('/<action>/', endpoint=(RootController, RootController.otheraction)).

Thanks a lot.
Cosmia
 
C

Cosmia Luna

Cosmia said:
I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do
nothing pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

class set_class:
def __init__(self, method):
self.method = method
def __get__(self, instance, class_):
if instance is None:
method = self.method
def f(*args, **kw):
return method(*args, **kw)
f.im_class = class_
f.__name__ = method.__name__
return f
return self.method.__get__(instance, class_)

class Foo:
def __init__(self, name):
self.name = name
@set_class
def bar(self):
print("%s says hello from bar()" % self)
def __str__(self):
return self.name

class Bar(Foo):
pass

assert Foo.bar.im_class is Foo
assert Bar.bar.im_class is Bar

Foo("Fred").bar()
Foo.bar(Foo("Fred"))

Bar("Fred").bar()
Bar.bar(Bar("Fred"))

The cleaner approach is probably:

Rule('/<action>/', endpoint=(RootController, RootController.otheraction))
...
Controller, method = endpoint
controller = Controller(Request(environ))
...
method(controller)


That's exactly what I want, and I think you're right, the approach below is cleaner.
Rule('/<action>/', endpoint=(RootController, RootController.otheraction)).

Thanks a lot.
Cosmia

Oh I'm wrong.
If I use a decorator, the decorator will NEVER get the owner class even in Python 2.X. The function is just plain function instead of unbound method before the code of a class is fully evaluated. So the decorator ALWAYS receives a plain function.

I'll look into the module inspect and try to get the frame of calling...

Cosmia
 
C

Cosmia Luna

Cosmia said:
I'm porting my existing work to Python 3.X, but...

class Foo:
def bar(self):
pass

mthd = Foo.bar

assert mthd.im_class is Foo # this does not work in py3k

So, how can I get a reference to Foo? This is important when writing
decorators, the only way I can think out is:

class Foo:
def bar(self):
'Foo' # manually declare the owner class
pass

mthd = Foo.bar

assert mthd.__globals__[mthd.__doc__] is Foo # this works

class Child(Foo):
def bar(self):
'Child' # I have to override all method defined by bar but do
nothing pass

child_mthd = Child.bar

assert child_mthd.__globals__[child_mthd.__doc__] is Child # this works

But the code above is quite ugly and abuses the __doc__. Is there any
equivalent in py3k of im_class?

class set_class:
def __init__(self, method):
self.method = method
def __get__(self, instance, class_):
if instance is None:
method = self.method
def f(*args, **kw):
return method(*args, **kw)
f.im_class = class_
f.__name__ = method.__name__
return f
return self.method.__get__(instance, class_)

class Foo:
def __init__(self, name):
self.name = name
@set_class
def bar(self):
print("%s says hello from bar()" % self)
def __str__(self):
return self.name

class Bar(Foo):
pass

assert Foo.bar.im_class is Foo
assert Bar.bar.im_class is Bar

Foo("Fred").bar()
Foo.bar(Foo("Fred"))

Bar("Fred").bar()
Bar.bar(Bar("Fred"))

The cleaner approach is probably:

Rule('/<action>/', endpoint=(RootController, RootController.otheraction))
...
Controller, method = endpoint
controller = Controller(Request(environ))
...
method(controller)


That's exactly what I want, and I think you're right, the approach below is cleaner.
Rule('/<action>/', endpoint=(RootController, RootController.otheraction)).

Thanks a lot.
Cosmia

Oh I'm wrong.
If I use a decorator, the decorator will NEVER get the owner class even in Python 2.X. The function is just plain function instead of unbound method before the code of a class is fully evaluated. So the decorator ALWAYS receives a plain function.

I'll look into the module inspect and try to get the frame of calling...

Cosmia
 
C

Cosmia Luna

I think I got the way to handle it but with small problem and probably at
unnecessary performance cost. If you're going to use it, be sure rewrite the
code and remove the lines which you don't need. Annnnd, test them, the code
below is only tested on py3.2, and may contains a lot of bugs even in py3.2.
You don't need it in py2.X, really.

----------------------------------BEGIN PYTHON----------------------------------
from functools import wraps
from types import FunctionType

CLASS_REF = 'im_class'

class Py2Type(type):
def __init__(cls, name, bases, dict_):
for k, v in dict_.items(): #ref3
if isinstance(v, FunctionType):
setattr(v, CLASS_REF, cls)
for base in bases:
for k, v in base.__dict__.items():
if isinstance(v, FunctionType) and k not in dict_:
@wraps(v)
def wrapper(*args, **kwargs):
return v(*args, **kwargs)
setattr(wrapper, CLASS_REF, cls)
dict_[k] = wrapper
setattr(cls, k, wrapper) #ref1
type.__init__(cls, name, bases, dict_) #ref2

Py2TypeBase = Py2Type('Py2TypeBase', (object, ), {})
-----------------------------------END PYTHON-----------------------------------

And any class inherit(directly or indirectly) from Py2TypeBase can have them
unbound method has a 'im_class' attribute reference to the owner class.

Usage:

Just subclass Py2TypeBase and write anything you want.

----------------------------------BEGIN PYTHON----------------------------------
class Foo(Py2TypeBase):
def get(self): pass
def set(self): pass

class Bar(Foo):
def get(self): pass

assert Foo.get.im_class is Foo
assert Foo.set.im_class is Foo
assert Bar.get.im_class is Bar
assert Bar.set.im_class is Bar

# the code above works, but only the explicitly defined will has the
# im_class attribute, so

assert Foo.__init__.im_class is Foo # this doesn't work.

-----------------------------------END PYTHON-----------------------------------

But it seems that the last line(#ref2) in the Py2Type.__init__ does not work at
all. It seems really weird, 'type' is an instance of 'type' itself, I'm not sure
if I'm calling the unbound method __init__ or bound method __init__.

And the original code does not have the line(#ref1), but because line(#ref2)
does not work, I added them.

It seems type.__new__ calls type.__init__ before it calls Py2Type.__init__,
because dict_ is already copied to cls.__dict__ at line(#ref3).

But 'type' is written in C or some other, it's beyond my ability to read the
code. Can anyone tell me what python does when a class block is fully evaluated
kindly?

Regards,
Cosmia
 
C

Cosmia Luna

I think I got the way to handle it but with small problem and probably at
unnecessary performance cost. If you're going to use it, be sure rewrite the
code and remove the lines which you don't need. Annnnd, test them, the code
below is only tested on py3.2, and may contains a lot of bugs even in py3.2.
You don't need it in py2.X, really.

----------------------------------BEGIN PYTHON----------------------------------
from functools import wraps
from types import FunctionType

CLASS_REF = 'im_class'

class Py2Type(type):
def __init__(cls, name, bases, dict_):
for k, v in dict_.items(): #ref3
if isinstance(v, FunctionType):
setattr(v, CLASS_REF, cls)
for base in bases:
for k, v in base.__dict__.items():
if isinstance(v, FunctionType) and k not in dict_:
@wraps(v)
def wrapper(*args, **kwargs):
return v(*args, **kwargs)
setattr(wrapper, CLASS_REF, cls)
dict_[k] = wrapper
setattr(cls, k, wrapper) #ref1
type.__init__(cls, name, bases, dict_) #ref2

Py2TypeBase = Py2Type('Py2TypeBase', (object, ), {})
-----------------------------------END PYTHON-----------------------------------

And any class inherit(directly or indirectly) from Py2TypeBase can have them
unbound method has a 'im_class' attribute reference to the owner class.

Usage:

Just subclass Py2TypeBase and write anything you want.

----------------------------------BEGIN PYTHON----------------------------------
class Foo(Py2TypeBase):
def get(self): pass
def set(self): pass

class Bar(Foo):
def get(self): pass

assert Foo.get.im_class is Foo
assert Foo.set.im_class is Foo
assert Bar.get.im_class is Bar
assert Bar.set.im_class is Bar

# the code above works, but only the explicitly defined will has the
# im_class attribute, so

assert Foo.__init__.im_class is Foo # this doesn't work.

-----------------------------------END PYTHON-----------------------------------

But it seems that the last line(#ref2) in the Py2Type.__init__ does not work at
all. It seems really weird, 'type' is an instance of 'type' itself, I'm not sure
if I'm calling the unbound method __init__ or bound method __init__.

And the original code does not have the line(#ref1), but because line(#ref2)
does not work, I added them.

It seems type.__new__ calls type.__init__ before it calls Py2Type.__init__,
because dict_ is already copied to cls.__dict__ at line(#ref3).

But 'type' is written in C or some other, it's beyond my ability to read the
code. Can anyone tell me what python does when a class block is fully evaluated
kindly?

Regards,
Cosmia
 
I

Ian Kelly

But it seems that the last line(#ref2) in the Py2Type.__init__ does not work at
all.

I'm not sure what you're expecting it to do, but type.__init__ does
not actually do anything
It seems really weird, 'type' is an instance of 'type' itself, I'm not sure
if I'm calling the unbound method __init__ or bound method __init__.

type.__init__ is never bound.
It seems type.__new__ calls type.__init__ before it calls Py2Type.__init__,
because dict_ is already copied to cls.__dict__ at line(#ref3).

No, type.__new__ does not call type.__init__ at all. Rather, it is
type.__new__ that is responsible for copying the dict, not
type.__init__. For this reason you should override type.__new__ in
your metaclass, not type.__init__.

Cheers,
Ian
 

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

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top