467,135 Members | 1,138 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

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

Replace Whole Object Through Object Method

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

Jun 26 '06 #1
  • viewed: 1647
Share:
23 Replies
Le lundi 26 juin 2006 17:57, di*************@gmail.com 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 ? return 1 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
Jun 26 '06 #2
di*************@gmail.com wrote:
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.
def dumbfactory(): .... class Dumb(object): pass
.... class Dummy: pass
.... return Dumb, Dummy
.... globals() {'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', '__doc__': None, 'dumbfactory': <function dumbfactory at
0x2aaaaab66e60>} def fun(): .... dumb, dummy = dumbfactory()
.... return
.... fun()
globals() {'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', 'fun': <function fun at 0x2aaaaab66ed8>, '__doc__': None,
'dumbfactory': <function dumbfactory at 0x2aaaaab66e60>}
Looks like dumb and dummy won't get listed... And also:
class Mymeta(type): .... pass
.... class Foo(object): .... __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 ?
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 26 '06 #3

Maric Michaud wrote:
Le lundi 26 juin 2006 17:57, di*************@gmail.com 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.
if 'classobj' in str(type(object)):

Why don't you test the type directly ?


Thanks.
return 1

Python has boolean for clarity.


Thanks.
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)


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

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.
Any answers my primary question though?

Advance thanks to all who can help...


--
_____________

Maric Michaud
_____________

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


Jun 26 '06 #4

Bruno Desthuilliers wrote:
di*************@gmail.com wrote:
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.
def dumbfactory(): ... class Dumb(object): pass
... class Dummy: pass
... return Dumb, Dummy
... globals() {'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', '__doc__': None, 'dumbfactory': <function dumbfactory at
0x2aaaaab66e60>} def fun(): ... dumb, dummy = dumbfactory()
... return
... fun()
globals() {'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', 'fun': <function fun at 0x2aaaaab66ed8>, '__doc__': None,
'dumbfactory': <function dumbfactory at 0x2aaaaab66e60>}
Looks like dumb and dummy won't get listed... And also:
class Mymeta(type): ... pass
... class Foo(object): ... __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...
....
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 ?


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


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"


Jun 26 '06 #5

Maric Michaud wrote:
....
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__.


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.

Jun 26 '06 #6
di*************@gmail.com wrote:
Maric Michaud wrote:

(snip)
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.


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...
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 26 '06 #7
di*************@gmail.com a écrit :
Bruno Desthuilliers wrote: (snip)

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.


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).
Jun 26 '06 #8

Bruno Desthuilliers wrote:
di*************@gmail.com a écrit :
Bruno Desthuilliers wrote:

(snip)

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.


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


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.

Jun 26 '06 #9
di*************@gmail.com a écrit :
Bruno Desthuilliers wrote:
di*************@gmail.com a écrit :
Bruno Desthuilliers wrote:
(snip)
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.


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:

(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.
Jun 27 '06 #10
Le lundi 26 juin 2006 22:37, di*************@gmail.com 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
Jun 27 '06 #11

Maric Michaud wrote:
Le lundi 26 juin 2006 22:37, di*************@gmail.com 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.


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.

--
_____________

Maric Michaud
_____________

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


Jun 27 '06 #12

Bruno Desthuilliers wrote:
(snip)

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) ?


They have unique attributes, conflict is not a problem. What do you
mean by init-on?
Furthermore, this is a
very simple case and ultimately in my program an object


*Any* object ?-) Yes, any real-world object modeled in my program.
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 ?)


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.

Jun 27 '06 #13
di*************@gmail.com wrote:
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>

Jun 27 '06 #14
I V
On Mon, 26 Jun 2006 19:40:52 -0700, digitalorganics wrote:
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()

Jun 27 '06 #15
Maric Michaud wrote:
Le lundi 26 juin 2006 22:37, di*************@gmail.com 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


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 !-)

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 27 '06 #16
I V wrote:
On Mon, 26 Jun 2006 19:40:52 -0700, digitalorganics wrote:
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_,


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.

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


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 27 '06 #17
Bruno Desthuilliers wrote:
As a matter of fact, in Python, the class is an attribute of an object.


except when it isn't.
def add_role(self, role_class):
self.roles.append(role_class(self))


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


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

</F>

Jun 27 '06 #18
Fredrik Lundh wrote:
Bruno Desthuilliers wrote:

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

except when it isn't.


Which are the cases where it isn't ?
def add_role(self, role_class):
self.roles.append(role_class(self))


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

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


Yes. But garbage collection is not cost-free AFAIK.
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 27 '06 #19
On 6/28/06, bussiere <bu**************@gmail.com> wrote:
I've read thsi documentation n:
http://docs.python.org/dev/whatsnew/whatsnew25.html
is there a way to have it in a more printable form ?


Yep: http://www.python.org/ftp/python/doc/2.5b1/
Jun 28 '06 #20
Hi Bruno :)

On 2006-06-27 10:30, Bruno Desthuilliers wrote:
FWIW, a good part of the canonical design patterns are mostly workaround
the lack of flexibility in languages like C++ and Java.
May be, but that doesn't exclude that some patterns are also
useful in Python. :-)
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.
It may be the "simplest" but it might not be the most "natural"
in terms of the problem domain.

At the Informationsdienst Wissenschaft ( http://idw-online.de )
we had a similar design problem. There, a person can have many
roles, like subscriber, journalist, public info officer etc. We
found it most natural to implement this with the actor/role
pattern, as I V described it.
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.
You don't have to, unless both classes have a __del__ method and
the garbage collector thus can't decide which to collect/delete
first.
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.
It might be "legal" but it also may be confusing. I would use the
design that makes the software easiest to maintain in the long
run. (If you don't know what the long run is, consider the
"medium run" and refactor later. :) )
Now I do agree that it can become tricky to manage correctly wrt/ mro
rules !-)


See? ;-) Software shouldn't be tricky (or only as tricky as
necessary). I value clarity over cleverness.

Stefan
Jul 1 '06 #21

di*************@gmail.com wrote:
How can an object replace itself using its own method? See the
following code
[code deleted]

At the risk of creating totally incomprehensible and
unmaintainable code, you need two things:

First, you can change the class of any new style
object by assigning to the __class__ attribute.

Second, you can create a new style class
on the fly with the three operand type(a, b, c) method.
See the builtin methods in the doc.

It's quite straightforward if you know what you're
doing. What's hard is to create a conceptual model
that won't be an instant winner in an obfuscated code
contest.

John Roth


Jul 1 '06 #22

Fredrik Lundh wrote:
di*************@gmail.com wrote:
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 ?
Why not just do what? And the way you use the term abuse, almost as if
Python's class mechanism was someone's child...
>
I suspect that your team would prefer if you got your inspiration from
GoF instead of Goldberg.

</F>
Jul 4 '06 #23
Point well taken, and indeed a brilliant solution. Thank you I V for
demonstrating so clearly.

I V wrote:
On Mon, 26 Jun 2006 19:40:52 -0700, digitalorganics wrote:
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()
Jul 4 '06 #24

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by Roose | last post: by
12 posts views Thread by Brian | last post: by
7 posts views Thread by Jeff Grippe | last post: by
1 post views Thread by shapper | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.