Replace Whole Object Through Object Method

D

digitalorganics

How can an object replace itself using its own method? See the
following code:

class Mixin:
def mixin(object, *classes):
NewClass = type('Mixin', (object.__class__,) + classes, {})
newobj = NewClass()
newobj.__dict__.update(object.__dict__)
return newobj

def isClass(object):
if 'classobj' in str(type(object)):
return 1
elif "'type'" in str(type(object)):
return 1
else:
return 0
def listClasses():
classes = []
for eachobj in globals().keys():
if isClass(globals()[eachobj]):
classes.append(globals()[eachobj])
print eachobj
return classes

def MixInto(Class, Mixin):
if Mixin not in Class.__bases__:
Class.__bases__ += (Mixin,)
------------------------------------------------------------------------

Okay, so the mixin function becomes part of whatever class I choose and
hence its instances, but the problem is that the way I currently have
it setup mixin() returns a new object, instead of replacing whatever
class instance that calls it into that new object. I hope I'm making
sense here.

Basically what I need is for the method to be able to find out the name
of the instance, then I can just go to the globals dictionary to do the
replacement.

Advance thanks to all who can help...
 
M

Maric Michaud

Le lundi 26 juin 2006 17:57, (e-mail address removed) a écrit :
How can an object replace itself using its own method? See the
following code:

class Mixin:
def mixin(object, *classes):
NewClass = type('Mixin', (object.__class__,) + classes, {})
newobj = NewClass()
newobj.__dict__.update(object.__dict__)
return newobj

Variables in python are names, not the objects, and instances shouldn't know
nothing about how they are referenced.

I guess what you want to do is, in fact, very simple somethig like :

a = SomeClass()
a = a.some_method_wich_return_a_new_object()

or :

for k, v in globals().iteritems() :
if isinstance(v, SomeClass) :
globlals()[k] = v.some_method_wich_return_a_new_object()

def isClass(object): Don't mask builtin names.
if 'classobj' in str(type(object)):
Why don't you test the type directly ?
Python has boolean for clarity.
elif "'type'" in str(type(object)):
return 1
else:
return 0
should be :

import types

def isClass(object_) :
if isinstance(object_, type) :
return True # new style class
elif isinstance(object_, types.ClassType) :
return True # old-style class
else : return False

or if you don't need to diferentiate the cases :

def isClass(object_) :
return isinstance(object_, type) or \
isinstance(object_, types.ClassType)


def listClasses():
classes = []
for eachobj in globals().keys():
if isClass(globals()[eachobj]):
classes.append(globals()[eachobj])
print eachobj
return classes

def MixInto(Class, Mixin):
if Mixin not in Class.__bases__:
Class.__bases__ += (Mixin,)

This doesn't work in most cases (with new style classes), better recreat a
type which inherit from Class and Mixin, or Class.__dict__ with
Mixin.__dict__.
------------------------------------------------------------------------

Okay, so the mixin function becomes part of whatever class I choose and
hence its instances, but the problem is that the way I currently have
it setup mixin() returns a new object, instead of replacing whatever
class instance that calls it into that new object. I hope I'm making
sense here.

Basically what I need is for the method to be able to find out the name
of the instance, then I can just go to the globals dictionary to do the
replacement.

Advance thanks to all who can help...

--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
 
B

Bruno Desthuilliers

How can an object replace itself using its own method?

AFAIK, It can't (but I can be wrong - some guru around ?).
See the
following code:

class Mixin:
def mixin(object, *classes):
NewClass = type('Mixin', (object.__class__,) + classes, {})
newobj = NewClass()
newobj.__dict__.update(object.__dict__)
return newobj

def isClass(object):
if 'classobj' in str(type(object)):
return 1
elif "'type'" in str(type(object)):
return 1
else:
return 0
def listClasses():
classes = []
for eachobj in globals().keys():
if isClass(globals()[eachobj]):
classes.append(globals()[eachobj])
print eachobj
return classes

FWIW:
Python 2.4.3 (#1, Jun 3 2006, 17:26:11)
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information..... class Dumb(object): pass
.... class Dummy: pass
.... return Dumb, Dummy
....{'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', '__doc__': None, 'dumbfactory': <function dumbfactory at
0x2aaaaab66e60>}.... dumb, dummy = dumbfactory()
.... return
....{'__builtins__': <module '__builtin__' (built-in)>, '__name__':

Looks like dumb and dummy won't get listed... And also:
.... pass
........ __metaclass__ = Mymeta
....
"'type'" in str(type(globals()['Mymeta']))
True

Looks like this will list metaclasses too... May or may not be a problem...
def MixInto(Class, Mixin):

You're aware that in this function's scope, the 'Mixin' arg name will
shadow the Mixin class name ? (sorry for asking dumb question).
if Mixin not in Class.__bases__:
Class.__bases__ += (Mixin,)
------------------------------------------------------------------------

Okay, so the mixin function becomes part of whatever class I choose and
hence its instances, but the problem is that the way I currently have
it setup mixin() returns a new object, instead of replacing whatever
class instance that calls it into that new object. I hope I'm making
sense here.

Basically what I need is for the method to be able to find out the name
of the instance, then I can just go to the globals dictionary to do the
replacement.

Advance thanks to all who can help...

Instead of exposing problems with your solution, you may want to expose
the real use case ?
 
D

digitalorganics

Maric said:
Le lundi 26 juin 2006 17:57, (e-mail address removed) a écrit :
How can an object replace itself using its own method? See the
following code:

class Mixin:
def mixin(object, *classes):
NewClass = type('Mixin', (object.__class__,) + classes, {})
newobj = NewClass()
newobj.__dict__.update(object.__dict__)
return newobj

Variables in python are names, not the objects, and instances shouldn't know
nothing about how they are referenced.

I guess what you want to do is, in fact, very simple somethig like :

a = SomeClass()
a = a.some_method_wich_return_a_new_object()

or :

for k, v in globals().iteritems() :
if isinstance(v, SomeClass) :
globlals()[k] = v.some_method_wich_return_a_new_object()

def isClass(object):
Don't mask builtin names.

You mean "object"? The shadow/mask only exists within the scope of the
function. But anyhow, point well taken.
Why don't you test the type directly ?
Thanks.

Python has boolean for clarity.
Thanks.

should be :

import types

def isClass(object_) :
if isinstance(object_, type) :
return True # new style class
elif isinstance(object_, types.ClassType) :
return True # old-style class
else : return False

or if you don't need to diferentiate the cases :

def isClass(object_) :
return isinstance(object_, type) or \
isinstance(object_, types.ClassType)

Very clean! Thank you.
def listClasses():
classes = []
for eachobj in globals().keys():
if isClass(globals()[eachobj]):
classes.append(globals()[eachobj])
print eachobj
return classes

def MixInto(Class, Mixin):
if Mixin not in Class.__bases__:
Class.__bases__ += (Mixin,)

This doesn't work in most cases (with new style classes), better recreat a
type which inherit from Class and Mixin, or Class.__dict__ with
Mixin.__dict__.

What doesn't work exactly? The whole purpose of the mixin is to add
functionality to the class and hence to all its instances on the fly.
Creating a new type would not achieve this, unless there's something
I'm missing (a very real possibility!). And what do you mean doesn't
work in most newstyleclass cases? Seems to be working just fine...

Any answers my primary question though?
 
D

digitalorganics

Bruno said:
How can an object replace itself using its own method?

AFAIK, It can't (but I can be wrong - some guru around ?).

FWIW:
Python 2.4.3 (#1, Jun 3 2006, 17:26:11)
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.... class Dumb(object): pass
... class Dummy: pass
... return Dumb, Dummy
...{'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', '__doc__': None, 'dumbfactory': <function dumbfactory at
0x2aaaaab66e60>}... dumb, dummy = dumbfactory()
... return
...{'__builtins__': <module '__builtin__' (built-in)>, '__name__':

Looks like dumb and dummy won't get listed... And also:
... pass
...... __metaclass__ = Mymeta
...
"'type'" in str(type(globals()['Mymeta']))
True

Looks like this will list metaclasses too... May or may not be a problem...
def MixInto(Class, Mixin):

You're aware that in this function's scope, the 'Mixin' arg name will
shadow the Mixin class name ? (sorry for asking dumb question).

No sorry necessary, but yes, I am aware of it. Poor programming
practice I'm sure...
....

Instead of exposing problems with your solution, you may want to expose
the real use case ?

***
I'm working with a team that's doing social modeling, and for example,
I need to model workers that at some point in the program may or may
not also become employers. Now, I want the workers to take on all
behaviors and attributes of an employer in addition to their
pre-existing "worker" behaviors and attributes. Also, as I'm sure you
guessed, the workers' attributes need to retain their values at that
point in the program, so a brand new worker-employer object wouldn't in
itself do the trick.
***
 
D

digitalorganics

Maric Michaud wrote:
....
This doesn't work in most cases (with new style classes), better recreat a
type which inherit from Class and Mixin, or Class.__dict__ with
Mixin.__dict__.

I think I've discovered precisely what you mean about problem with new
style classes. Do you know why it doesn't work for them? As I pointed
out, creating a new type doesn't achieve the same thing. Any
workarounds? Thanks.
 
B

Bruno Desthuilliers

Maric Michaud wrote:
(snip)



What doesn't work exactly? The whole purpose of the mixin is to add
functionality to the class and hence to all its instances on the fly.

very naïve solution:

def mixin(obj):

def someFunc(self, ...)
# code here
def someOtherFunc(self, ...)
# code here

cls = obj.__class__
cls.someFunc = someFunc
cls.someOtherFunc = someOtherFunc

Just a bit less nïave solution:

def mixin(func):
func._mixin = True
return func

def mixable(func):
return getattr(attr, '_mixin', False):

class Mixin(object):
@mixin
def someFunc(self, ...):
# code here

@mixin
def someOtherFunc(self, ...)
# code here


def mix(cls, mixincls):
for name in dir(mixincls):
attr = getattr(mixincls, name)
if callable(attr) and mixable(attr):
setattr(cls, name, attr)


Of course, one can do much better...
 
D

digitalorganics

Bruno said:
(e-mail address removed) a écrit :

If I understand correctly, only some of the existing workers will become
employers ?


wrt/ behaviors, it's easy as pie. Attributes (I mean instance
attributes) are another problem, but I don't have enough informations to
deal with this problem here.


Here's a simple stupid possible solution:

class Worker(object):
def __init__(self, ...)
# init code here

# behaviours here

def becomeEmployer(self):
self.___class__ = Employer

class Employer(Worker):
# behaviours here


w = Worker(...)
w.becomeEmployer()

Note that there's no initializer in the Employer class - it wouldn't get
called anyway (not automatically at least).

Won't work because there will be employers that aren't workers.
And yes, only some workers will become employers, but also only some
employers will also be workers (at some point in program). Let me be
more clear:

workers
--> subset of workers --become--> employers
employers
--> subset of employers --become--> workers

It is very important that both should maintain attribute values,
regardless of whether they take on new "roles". Furthermore, this is a
very simple case and ultimately in my program an object should be able
to dynamically take on a multitude of roles (classes of behavior)
without mucking at all with their pre-existing states.
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
Bruno Desthuilliers wrote: (snip)


I'm working with a team that's doing social modeling, and for example,
I need to model workers that at some point in the program may or may
not also become employers.

If I understand correctly, only some of the existing workers will become
employers ?
Now, I want the workers to take on all
behaviors and attributes of an employer in addition to their
pre-existing "worker" behaviors and attributes.

wrt/ behaviors, it's easy as pie. Attributes (I mean instance
attributes) are another problem, but I don't have enough informations to
deal with this problem here.
Also, as I'm sure you
guessed, the workers' attributes need to retain their values at that
point in the program, so a brand new worker-employer object wouldn't in
itself do the trick.

Here's a simple stupid possible solution:

class Worker(object):
def __init__(self, ...)
# init code here

# behaviours here

def becomeEmployer(self):
self.___class__ = Employer

class Employer(Worker):
# behaviours here


w = Worker(...)
w.becomeEmployer()

Note that there's no initializer in the Employer class - it wouldn't get
called anyway (not automatically at least).
 
M

Maric Michaud

Le lundi 26 juin 2006 22:37, (e-mail address removed) a écrit :
Won't work because there will be employers that aren't workers.
And yes, only some workers will become employers, but also only some
employers will also be workers (at some point in program). Let me be
more clear:

workers
--> subset of workers --become--> employers
employers
--> subset of employers --become--> workers

It is very important that both should maintain attribute values,
regardless of whether they take on new "roles". Furthermore, this is a
very simple case and ultimately in my program an object should be able
to dynamically take on a multitude of roles (classes of behavior)
without mucking at all with their pre-existing states.

This seem to be a OO design problem and you clearly make a misuse of
inheritance, if a person can eventually have many roles, but doesn't have
this role for all his lifetime, then the person *is* not his roles.
That the meaning of inheritance, class B(A) means a B is a A.
The association between a person and his roles is obviously a 1-n association,
which can be rendered by different patterns (delegation, composition,
strategy, etc.).
You should google on "design patterns" and make your choice.

--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
 
D

digitalorganics

Maric said:
Le lundi 26 juin 2006 22:37, (e-mail address removed) a écrit :

This seem to be a OO design problem and you clearly make a misuse of
inheritance, if a person can eventually have many roles, but doesn't have
this role for all his lifetime, then the person *is* not his roles.
That the meaning of inheritance, class B(A) means a B is a A.
The association between a person and his roles is obviously a 1-n association,
which can be rendered by different patterns (delegation, composition,
strategy, etc.).
You should google on "design patterns" and make your choice.

A misuse of inheritance eh? Inheritance, like other language features,
is merely a tool. I happen to be using this tool to have my virtual
persons change roles at different points in their lifetime, as many
real people tend to do. Thus, at these points, B is indeed an A. What a
person is, whether in real life or in my program, is not static and
comes into definition uniquely for each moment (micro-moment, etc.) of
existence. Now, please, I have no intention of carrying the
conversation in such a silly direction, I wasn't inviting a discussion
on philosophy or some such. I seek to work the tools to my needs, not
the other way around.
 
D

digitalorganics

Bruno Desthuilliers wrote:
(snip)
Seems obvious. But just a question, BTW: do workers and employers share
the same attributes ? And if not, how do you intend to initialize the
employers attributes on workers (and the other way round) ?

They have unique attributes, conflict is not a problem. What do you
mean by init-on?
*Any* object ?-) Yes, any real-world object modeled in my program.


Multiple roles at the same time, or sequentially ? And in the first case
(which I assume), do you have the case of overriding behaviors ? And if
yes, how should the resolution order be defined ? And what about
attributes ? (I mean, do your 'roles' have specific attributes ?)

Multiple roles at the same time, with specific attributes for each.
Overriding behaviors is not a problem as each has unique behaviors.
Common behaviors are sourced from a base class. In the case of multiple
simultaneous roles, overwriting these common behaviors with duplicates
isn't really a problem in the sense that the dups are indeed identical
to the previous code.
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
(snip)

Won't work because there will be employers that aren't workers.

Then don't subclass Employer from Worker !-)

(don't mind, just kidding)
And yes, only some workers will become employers,
>
but also only some
employers will also be workers (at some point in program). Let me be
more clear:

workers
--> subset of workers --become--> employers
employers
--> subset of employers --become--> workers

It is very important that both should maintain attribute values,
regardless of whether they take on new "roles".

Seems obvious. But just a question, BTW: do workers and employers share
the same attributes ? And if not, how do you intend to initialize the
employers attributes on workers (and the other way round) ?
Furthermore, this is a
very simple case and ultimately in my program an object

*Any* object ?-)
should be able
to dynamically take on a multitude of roles (classes of behavior)
> without mucking at all with their pre-existing states.

Multiple roles at the same time, or sequentially ? And in the first case
(which I assume), do you have the case of overriding behaviors ? And if
yes, how should the resolution order be defined ? And what about
attributes ? (I mean, do your 'roles' have specific attributes ?)


FWIW, just another simple (and very Q&D) snippet:

class ObjectWithRoles(object):
def _change(self, *bases):
self.__class__ = type(self.__class__.__name__, bases, {})

def has_role(self, role):
return role in self.__class__.__bases__

def add_role(self, role):
if not self.has_role(role):
self._change(self.__class__, role)

def remove_role(self, role):
if self.has_role(role):
self._change(*(cls for cls in self.__class__.__bases__ \
if cls is not role))


NB : Not tested (and not sure what it'll do) with roles subclassing
other roles, or ObjectWithRoles as roles...

wrt/ per-role attributes, you'd of course need to pass them to
add_role(). A convenient way of maintaining some sanity here would be to
use descriptors for all of these attributes, and store their values in a
per-role dict, with the role name as attribute name.
 
F

Fredrik Lundh

I'm working with a team that's doing social modeling, and for example,
I need to model workers that at some point in the program may or may
not also become employers. Now, I want the workers to take on all
behaviors and attributes of an employer in addition to their
pre-existing "worker" behaviors and attributes. Also, as I'm sure you
guessed, the workers' attributes need to retain their values at that
point in the program, so a brand new worker-employer object wouldn't in
itself do the trick.

so why not just do that, instead of trying to come up with overly
convoluted ways to abuse a class mechanism that you don't fully understand ?

I suspect that your team would prefer if you got your inspiration from
GoF instead of Goldberg.

</F>
 
I

I V

A misuse of inheritance eh? Inheritance, like other language features,
is merely a tool. I happen to be using this tool to have my virtual
persons change roles at different points in their lifetime, as many
real people tend to do. Thus, at these points, B is indeed an A. What a
person is, whether in real life or in my program, is not static and
comes into definition uniquely for each moment (micro-moment, etc.) of
existence. Now, please, I have no intention of carrying the
conversation in such a silly direction, I wasn't inviting a discussion
on philosophy or some such. I seek to work the tools to my needs, not
the other way around.

But thinking about the problem in the vocabulary provided by the
programming language can be helpful in coming up with a solution. If
inheritance tells you what an object _is_, and membership tells you what a
role _has_, and a role is something that a person has, that suggests
that an implementation where roles are members of a person might be
simpler than trying to use inheritance. Like, for instance:

class Role(object):
def __init__(self, person):
self.person = person


class Worker(Role):
def do_work(self):
print self.name, "is working"


class Employer(Role):

def __init__(self, person):
Role.__init__(self, person)
self.employees = []


def add_employee(self, worker):
self.employees.append(worker)


def boss_people_around(self):
for employee in employees:
print self.name, "is telling", employee.name, "what to do"


class Person(object):

def __init__(self, name):
self.roles = []
self.name = name


def add_role(self, role_class):
self.roles.append(role_class(self))


def forward_to_role(self, attr):
for role in self.roles:
try:
return getattr(role, attr)
except AttributeError:
pass
raise AttributeError(attr)


def __getattr__(self, attr):
self.forward_to_role(attr)


bill = Person('Bill')
bill.add_role(Worker)

bob = Person('Bob')
bob.add_role(Employer)

bill.work()
bob.boss_people_around()
 
B

Bruno Desthuilliers

Maric said:
Le lundi 26 juin 2006 22:37, (e-mail address removed) a écrit :



This seem to be a OO design problem
Obviously.

and you clearly make a misuse of
inheritance,

Chapter and verse, please ?
s/misuse/creative use/
if a person can eventually have many roles, but doesn't have
this role for all his lifetime, then the person *is* not his roles.

And ? In a dynamically typed language, inheritance is about
implementation, not subtyping. The class of an object is nothing more
than an attribute, and as such is not necessarily fixed for the lifetime
of the object.
That the meaning of inheritance, class B(A) means a B is a A.
The association between a person and his roles is obviously a 1-n association,
which can be rendered by different patterns (delegation, composition,
strategy, etc.).

You've learned your lessons well. That's fine. Now please understand
that there's a huge difference between the book (usually based on static
some static language) and dynamic OOPLs. IOW : free your mind.

In Python, you can dynamically change the class of an object at runtime.
And the attribute lookup rule is to first lookup the object, then the
class (which is itself an object FWIW). So you can see the object/class
relationship as a somewhat specialised composition/delegation
relationship. In fact, in Python, a class is both an object factory and
delegatee.
You should google on "design patterns" and make your choice.

FWIW, a good part of the canonical design patterns are mostly workaround
the lack of flexibility in languages like C++ and Java. The Strategy
pattern's simplest Python implementation is to dynamically replace a
method on a per-object basis. The State pattern's simplest
implementation in Python is to dynamically change the class of an object.

Of course, one of the canonical solutions to the OP's problem is to use
composition/delegation. But doing it the canonical way would imply
creating instances of the role objects and passing them the instance as
param so they can access it's attributes. It works, but it creates a
cyclic dependancy between the object and it's roles, so you would have
to use weakrefs. Dynamically creating new classes with the appropriate
bases and assigning them to the object's __class__ attribute is another
way to achieve the same result, and it's perfectly legal.

Now I do agree that it can become tricky to manage correctly wrt/ mro
rules !-)
 
B

Bruno Desthuilliers

I said:
But thinking about the problem in the vocabulary provided by the
programming language can be helpful in coming up with a solution. If
inheritance tells you what an object _is_,

It's not so clear in Python, cf my answer to Maric on this point.
and membership tells you what a
role _has_, and a role is something that a person has,

As a matter of fact, in Python, the class is an attribute of an object.
So it is really something that an object "have". And this relationship
is not carved in stone - it's perfectly legal to modify it at runtime.
that suggests
that an implementation where roles are members of a person might be
simpler than trying to use inheritance. Like, for instance:

class Role(object):
def __init__(self, person):
self.person = person
(snip)

class Person(object):

def __init__(self, name):
self.roles = []
self.name = name


def add_role(self, role_class):
self.roles.append(role_class(self))

And here you create a circular reference between object and roles...

def forward_to_role(self, attr):
for role in self.roles:
try:
return getattr(role, attr)
except AttributeError:
pass
raise AttributeError(attr)

This could as well be directly in __getattr__, and would avoid a useless
method call.
 
F

Fredrik Lundh

Bruno said:
As a matter of fact, in Python, the class is an attribute of an object.

except when it isn't.
And here you create a circular reference between object and roles...

and ? Python has a garbage collector, you know...

</F>
 

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,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top