By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,907 Members | 1,932 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,907 IT Pros & Developers. It's quick & easy.

Dynamic subclassing ?

P: n/a
I've got an instance of a class, ex :

b=gtk.Button()

I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !

In fact, i've got my instance "b", and another class "MoreMethods"

class MoreMethods:
def sayHello(self):
print "hello"

How could i write ...

"b = b + MoreMethods"

so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :

- b.set_label("k")
- b.sayHello()

I can't find the trick, but i'm pretty sure it's possible in an easy
way.
Help is welcome
thanx

May 12 '07 #1
Share this Question
Share on Google+
16 Replies


P: n/a
manatlan a écrit :
I've got an instance of a class, ex :

b=gtk.Button()

I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods.
You don't even need setattr() here, you can set the attributes directly.

But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !

In fact, i've got my instance "b", and another class "MoreMethods"

class MoreMethods:
def sayHello(self):
print "hello"

How could i write ...

"b = b + MoreMethods"

so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :

- b.set_label("k")
- b.sayHello()

I can't find the trick, but i'm pretty sure it's possible in an easy
way.
You don't necessarily need subclassing here. What you want is a typical
use case of the Decorator pattern:

class MoreMethods(object):
def __init__(self, button):
self._button = button

def sayHello(self):
print "hello"

def __getattr__(self, name):
return getattr(self._button, name)

def __setattr__(self, name, value):
if name in dir(self._button):
setattr(self._button, name, value)
else:
object.__setattr__(self, name, value)

b = MoreMethods(gtk.Button())
b.set_label("k")
b.say_hello()

May 12 '07 #2

P: n/a
On 12 mai, 17:00, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
manatlan a écrit :
I've got an instance of a class, ex :
b=gtk.Button()
I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods.

You don't even need setattr() here, you can set the attributes directly.
But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
In fact, i've got my instance "b", and another class "MoreMethods"
class MoreMethods:
def sayHello(self):
print "hello"
You don't necessarily need subclassing here. What you want is a typical
use case of the Decorator pattern:

class MoreMethods(object):
def __init__(self, button):
self._button = button

def sayHello(self):
print "hello"

def __getattr__(self, name):
return getattr(self._button, name)

def __setattr__(self, name, value):
if name in dir(self._button):
setattr(self._button, name, value)
else:
object.__setattr__(self, name, value)

b = MoreMethods(gtk.Button())
b.set_label("k")
b.say_hello()
except that "b" is not anymore a "gtk.Button", but a "MoreMethods"
instance ...
i'd like that "b" stay a "gtk.Button" ...

May 12 '07 #3

P: n/a
I've got an instance of a class, ex :
>
b=gtk.Button()

I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !

In fact, i've got my instance "b", and another class "MoreMethods"

class MoreMethods:
def sayHello(self):
print "hello"

How could i write ...

"b = b + MoreMethods"

so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :

- b.set_label("k")
- b.sayHello()

I can't find the trick, but i'm pretty sure it's possible in an easy
way.
How about:

class MoreMethods:
def sayHello(self):
print "hello"

class myButton( gtk.Button, MoreMethods ):
pass

b = myButton( )

isinstance( b, gtk.Button ) # True
b.sayHello( ) # "hello"
Daniel
May 12 '07 #4

P: n/a
On 12 mai, 18:38, "Daniel Nogradi" <nogr...@gmail.comwrote:
I've got an instance of a class, ex :
b=gtk.Button()
I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
In fact, i've got my instance "b", and another class "MoreMethods"
class MoreMethods:
def sayHello(self):
print "hello"
How could i write ...
"b = b + MoreMethods"
so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :
- b.set_label("k")
- b.sayHello()
I can't find the trick, but i'm pretty sure it's possible in an easy
way.

How about:

class MoreMethods:
def sayHello(self):
print "hello"

class myButton( gtk.Button, MoreMethods ):
pass

b = myButton( )

isinstance( b, gtk.Button ) # True
b.sayHello( ) # "hello"
yes, but it needs to recreate an instance (of mybutton) ...
i can't do that, in my context.
The only things i've got is my instance "b" (which can be whatever
object).
i'd like to add methods/attributes to this instance, by adding a
heritage of another class.
Daniel
thanks

May 12 '07 #5

P: n/a
manatlan wrote:
I can't find the trick, but i'm pretty sure it's possible in an easy
way.
It's somewhat easy, boot looks ugly to me. Maybe someone has a more
elegant solution:

In [6]: import new

In [13]: class Button:
....: def buttonFunc(self):
....: pass

In [14]: class ExtensionClass:
....: def extendedMethod(self):
....: pass

In [15]: hybrid = new.instance(Button,
Button.__dict__.update(ExtensionClass.__dict__))

In [17]: dir(hybrid)
Out[17]: ['__doc__', '__module__', 'buttonFunc', 'extendedMethod']

Seems to do what you want it to do.

HTH,
Karlo.



May 12 '07 #6

P: n/a
I've got an instance of a class, ex :
b=gtk.Button()
I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
In fact, i've got my instance "b", and another class "MoreMethods"
class MoreMethods:
def sayHello(self):
print "hello"
How could i write ...
"b = b + MoreMethods"
so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :
- b.set_label("k")
- b.sayHello()
I can't find the trick, but i'm pretty sure it's possible in an easy
way.
How about:

class MoreMethods:
def sayHello(self):
print "hello"

class myButton( gtk.Button, MoreMethods ):
pass

b = myButton( )

isinstance( b, gtk.Button ) # True
b.sayHello( ) # "hello"

yes, but it needs to recreate an instance (of mybutton) ...
i can't do that, in my context.
The only things i've got is my instance "b" (which can be whatever
object).
i'd like to add methods/attributes to this instance, by adding a
heritage of another class.
I think that is not possible, at least in a simple way (there might be
a complicated way of messing with the MRO). Please anyone correct me
if I was wrong.

Daniel
May 12 '07 #7

P: n/a
manatlan wrote:
I've got an instance of a class, ex :

b=gtk.Button()

I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !

In fact, i've got my instance "b", and another class "MoreMethods"

class MoreMethods:
def sayHello(self):
print "hello"

How could i write ...

"b = b + MoreMethods"
You can simply bind the methods you want to add to the Button instance.
That means doing the equivalent of ``b.sayHello = sayHello.__get__(b)``.
For example::
>>class Button(object):
... def set_label(self, label):
... print 'setting label:', label
...
>>def add_methods(obj, cls):
... for name, value in cls.__dict__.items():
... if callable(value) and hasattr(value, '__get__'):
... setattr(obj, name, value.__get__(obj, type(obj)))
...
>>b = Button()
b.set_label('k')
setting label: k
>>b.say_hello()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
AttributeError: 'Button' object has no attribute 'say_hello'
>>class MoreMethods(object):
... def say_hello(self):
... print 'hello'
...
>>add_methods(b, MoreMethods)
b.set_label('m')
setting label: m
>>b.say_hello()
hello

HTH,

STeVe
May 12 '07 #8

P: n/a
manatlan <ma******@gmail.comwrote:
I've got an instance of a class, ex :

b=gtk.Button()

I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !

In fact, i've got my instance "b", and another class "MoreMethods"

class MoreMethods:
def sayHello(self):
print "hello"

How could i write ...

"b = b + MoreMethods"

so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :

- b.set_label("k")
- b.sayHello()

I can't find the trick, but i'm pretty sure it's possible in an easy
way.
I think what you're asking for is totally weird, and with just about
zero advantages compared with several saner alternatives that have
already been proposed in this thread and that you have rejects, but
sure, it's possible:

def addaclass(aninst, onemoreclass):
aninst.__class__ = type(aninst.__aclass__.__name__,
(aninst.__aclass__, onemoreclass), {})
Alex
May 12 '07 #9

P: n/a
On 13 mai, 01:24, a...@mac.com (Alex Martelli) wrote:
manatlan <manat...@gmail.comwrote:
I've got an instance of a class, ex :
b=gtk.Button()
I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
In fact, i've got my instance "b", and another class "MoreMethods"
class MoreMethods:
def sayHello(self):
print "hello"
How could i write ...
"b = b + MoreMethods"
so "b" will continue to be a gtk.Button, + methods/attributs of
MoreMethods (it's what i call "dynamic inheritance") ...so, things
like this should work :
- b.set_label("k")
- b.sayHello()
I can't find the trick, but i'm pretty sure it's possible in an easy
way.

I think what you're asking for is totally weird, and with just about
zero advantages compared with several saner alternatives that have
already been proposed in this thread and that you have rejects, but
sure, it's possible:

def addaclass(aninst, onemoreclass):
aninst.__class__ = type(aninst.__aclass__.__name__,
(aninst.__aclass__, onemoreclass), {})

Alex
I know it's weird ... and solutions given here are a lot saner. But i
can't do that at the creation of the instance, because it's not me who
has the creation process ... the only things i've got, it's the
instance

i tried :

class MoreMethods:
def sayHello(self):
print "hello"

def addaclass(aninst, onemoreclass):
aninst.__class__ = type(aninst.__class__.__name__,
(aninst.__class__, onemoreclass), {})

b=gtk.Button("the_label")
addaclass(b,MoreMethods)
print b.get_label()
print b.hello()

but got :
"TypeError: __class__ assignment: only for heap types"
on the last line ...

I begin to think that the only solution is to use the module new like
Karlo said ...

May 13 '07 #10

P: n/a
On 12 mai, 18:57, Karlo Lozovina <_karlo_@_mosor.netwrote:
manatlan wrote:
I can't find the trick, but i'm pretty sure it's possible in an easy
way.

It's somewhat easy, boot looks ugly to me. Maybe someone has a more
elegant solution:

In [6]: import new

In [13]: class Button:
....: def buttonFunc(self):
....: pass

In [14]: class ExtensionClass:
....: def extendedMethod(self):
....: pass

In [15]: hybrid = new.instance(Button,
Button.__dict__.update(ExtensionClass.__dict__))

In [17]: dir(hybrid)
Out[17]: ['__doc__', '__module__', 'buttonFunc', 'extendedMethod']

Seems to do what you want it to do.

HTH,
Karlo.
yes, i think it's the only solution ... it's weird
but it seems to be the only one ...
i will try that ...

May 13 '07 #11

P: n/a
On 12 mai, 20:47, Steven Bethard <steven.beth...@gmail.comwrote:
manatlan wrote:
I've got an instance of a class, ex :
b=gtk.Button()
I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods. But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
In fact, i've got my instance "b", and another class "MoreMethods"
class MoreMethods:
def sayHello(self):
print "hello"
How could i write ...
"b = b + MoreMethods"

You can simply bind the methods you want to add to the Button instance.
That means doing the equivalent of ``b.sayHello = sayHello.__get__(b)``.
For example::
>>class Button(object):
... def set_label(self, label):
... print 'setting label:', label
...
>>def add_methods(obj, cls):
... for name, value in cls.__dict__.items():
... if callable(value) and hasattr(value, '__get__'):
... setattr(obj, name, value.__get__(obj, type(obj)))
...
>>b = Button()
>>b.set_label('k')
setting label: k
>>b.say_hello()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
AttributeError: 'Button' object has no attribute 'say_hello'
>>class MoreMethods(object):
... def say_hello(self):
... print 'hello'
...
>>add_methods(b, MoreMethods)
>>b.set_label('m')
setting label: m
>>b.say_hello()
hello

HTH,

STeVe
Yes ! it seems very good ...
I will try that too
thanks a lot ...

class MoreMethods:
val=12
def hello(self):
self.val=13
return self.get_label()

def add_methods(obj, cls):
for name, value in cls.__dict__.items():
if callable(value) and hasattr(value, '__get__'):
setattr(obj, name, value.__get__(obj, type(obj)))
else:
setattr(obj, name, value)

b=gtk.Button("the_label")
add_methods(b,MoreMethods)
print b.get_label()
print b.val
print b.hello()
print b.val

May 13 '07 #12

P: n/a
On 13 mai, 10:04, manatlan <manat...@gmail.comwrote:
On 12 mai, 18:57, Karlo Lozovina <_karlo_@_mosor.netwrote:
manatlan wrote:
I can't find the trick, but i'm pretty sure it's possible in an easy
way.
It's somewhat easy, boot looks ugly to me. Maybe someone has a more
elegant solution:
In [6]: import new
In [13]: class Button:
....: def buttonFunc(self):
....: pass
In [14]: class ExtensionClass:
....: def extendedMethod(self):
....: pass
In [15]: hybrid = new.instance(Button,
Button.__dict__.update(ExtensionClass.__dict__))
In [17]: dir(hybrid)
Out[17]: ['__doc__', '__module__', 'buttonFunc', 'extendedMethod']
Seems to do what you want it to do.
HTH,
Karlo.

yes, i think it's the only solution ... it's weird
but it seems to be the only one ...
i will try that ...
in fact, the "new" solution adds methods to all "gtk.Button" and not a
specific instance ... it's not good for me
but thanks (i always forget the use of the "new" module for this kind
of things)

May 13 '07 #13

P: n/a
manatlan a écrit :
On 12 mai, 17:00, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
>>manatlan a écrit :

>>>I've got an instance of a class, ex :
>>>b=gtk.Button()
>>>I'd like to add methods and attributes to my instance "b".
I know it's possible by hacking "b" with setattr() methods.

You don't even need setattr() here, you can set the attributes directly.

>>>But i'd
like to do it with inheritance, a kind of "dynamic subclassing",
without subclassing the class, only this instance "b" !
>>>In fact, i've got my instance "b", and another class "MoreMethods"
>>>class MoreMethods:
def sayHello(self):
print "hello"

You don't necessarily need subclassing here. What you want is a typical
use case of the Decorator pattern:

class MoreMethods(object):
def __init__(self, button):
self._button = button

def sayHello(self):
print "hello"

def __getattr__(self, name):
return getattr(self._button, name)

def __setattr__(self, name, value):
if name in dir(self._button):
setattr(self._button, name, value)
else:
object.__setattr__(self, name, value)

b = MoreMethods(gtk.Button())
b.set_label("k")
b.say_hello()


except that "b" is not anymore a "gtk.Button", but a "MoreMethods"
instance ...
i'd like that "b" stay a "gtk.Button" ...
I don't understand why, but... Then write a function that "inject" all
the additionnal methods to your gtk.Button. Or do the
composition/delegation the other way round, and monkeypatch gtk.Button's
__getattr__.
May 13 '07 #14

P: n/a
manatlan <ma******@gmail.comwrote:
...
def addaclass(aninst, onemoreclass):
aninst.__class__ = type(aninst.__aclass__.__name__,
(aninst.__aclass__, onemoreclass), {})
...
b=gtk.Button("the_label")
addaclass(b,MoreMethods)
...
"TypeError: __class__ assignment: only for heap types"
on the last line ...
Ah, yes, a type can be coded in such a way that you simply can't
reassign the __class__ of its instances, and apparently gtk.Button is
coded that way.

If you're keen on __class__ reassigning, you'll have to wrap such
classes before instance creation time, e.g.:

class weirdGtkButton(gtk.Button): pass

and use

b = weirdGtkButton("the label")

to generate the instances. That, of course, assumes that gtk.Button
isn't ALSO coded in ways that impede subclassing (as for all I know it
might be -- I don't have GTK around to check), in which case instead of
subclassing it you need a trickier wrap-and-hold approach (and you can
never pass isinstance checks, which subclassing would let you pass).
Alex
May 13 '07 #15

P: n/a
Karlo Lozovina <_karlo_@_mosor.netwrote:
manatlan wrote:
>I can't find the trick, but i'm pretty sure it's possible in an easy
way.
It's somewhat easy, boot looks ugly to me. Maybe someone has a more
elegant solution:
In [6]: import new
In [13]: class Button:
....: def buttonFunc(self):
....: pass
In [14]: class ExtensionClass:
....: def extendedMethod(self):
....: pass
In [15]: hybrid = new.instance(Button,
Button.__dict__.update(ExtensionClass.__dict__))
In [17]: dir(hybrid)
Out[17]: ['__doc__', '__module__', 'buttonFunc', 'extendedMethod']
Seems to do what you want it to do.
HTH,
Karlo.
When I try something like this I run into a little problem:

class Foo:
def foo(self):
return "foo"
class Bar:
def bar(self):
return "bar"

f = Foo()
f.__dict__.update(Bar.__dict__)

... the problem is that while f now has a "bar" method it doesn't
work quite like a normal instance method:
>>f.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: bar() takes exactly 1 argument (0 given)
>>>
... though I can get by with f.bar(f)

This "new" module seems to be the key to it all; but the only
docs I have for that say:
>>help(new)
Help on module new:

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

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

MODULE DOCS
http://www.python.org/doc/current/lib/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.
... which sounds like a bad idea (from the word "Deprecated").


--
Jim Dennis,
Starshine: Signed, Sealed, Delivered

Jun 10 '07 #16

P: n/a
En Sun, 10 Jun 2007 18:16:12 -0300, James T. Dennis <ja******@idiom.com>
escribió:
When I try something like this I run into a little problem:

class Foo:
def foo(self):
return "foo"
class Bar:
def bar(self):
return "bar"

f = Foo()
f.__dict__.update(Bar.__dict__)

... the problem is that while f now has a "bar" method it doesn't
work quite like a normal instance method:

>>f.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: bar() takes exactly 1 argument (0 given)
>>>

... though I can get by with f.bar(f)
Bar.__dict__ contains *unbound* methods - that is, methods not linked to
any particular instance. If you copy them directly into f.__dict__ you
lose the "magic" that binds methods to instances.
You could store a bound method into the instance but it's not a good idea
(there are cyclic references).
I think the easiest way is to define a dynamic class (as the subject on
this old thread suggests):

pyf = Foo()
pyFoo2 = type("Foo2", (Foo,Bar), {})
pyf.__class__ = Foo2
pyf.bar()
'bar'

The code above changes the object class once it was created, but you don't
have to. Also, you don't have to use a different class name (altough it
may be confusing...):

pyf = type("Foo", (Foo,Bar), {})()
pyf.bar()
'bar'
This "new" module seems to be the key to it all;
It's almost useless now that types are callable.
but the only docs I have for that say:
>>>help(new)
Help on module new:
[...]
MODULE DOCS
http://www.python.org/doc/current/lib/module-new.html
Did you follow the above link?

--
Gabriel Genellina

Jun 10 '07 #17

This discussion thread is closed

Replies have been disabled for this discussion.