OO issues in python

A

Ali El Dada

hi all:

in python, when a class, say Father, has a member that itself is an
instance of another class, say Child, an instance of Father actually
only has a reference to a Child, not the Child object itself, right?

because i know that in eiffel they give the programmer the 2 options,
the second being implemented with an additional keyword (expanded) so as
the eiffel documentation says,

"Consider the example of a class covering the notion of car. Many cars
share the same originating_plant , but an engine belongs to just one
car. References represent the modeling relation "knows about";
subobjects, as permitted by expanded types, represent the relation "has
part", also known as aggregation. The key difference is that sharing is
possible in the former case but not in the latter"

the reason why i'm asking is that i want my Child() instance to know
things about the parent without having to explicitly pass them as
arguments. this is not working :(

eg code that doesn't work:

class Father:

def __init__(self):
self.a = 'foo'
self.son = Child()

class Child:

def __init__(self):
print f.a


f = Father()

thanks for any help..

Cheers,
Ali Dada
 
L

Lutz Horn

Hi,

* Ali El Dada said:
"Consider the example of a class covering the notion of car. Many
cars share the same originating_plant , but an engine belongs to
just one car. References represent the modeling relation "knows
about"; subobjects, as permitted by expanded types, represent the
relation "has part", also known as aggregation. The key difference
is that sharing is possible in the former case but not in the
latter"

The word "sharing" in the description of a reference means that many
instances of car could hold a reference to the same instance of
engine. Many cars would know about and share the same engine (this is
some stupid example :).

Aggregation means that one and only one car has a given instance of
an engine. Another car must have a different engine.
the reason why i'm asking is that i want my Child() instance to
know things about the parent without having to explicitly pass
them as arguments. this is not working :(

This has nothing to do with the difference between referencing and
aggregating. A Child doesn't know a thing about it's Father in both
cases.

For the Child to know about the Father you have to pass the Child a
reference to the Father.
eg code that doesn't work:

class Father:

def __init__(self):
self.a = 'foo'
self.son = Child()

class Child:

def __init__(self):
print f.a

What is f?
f = Father()

This instance of Father is out of scope for any method of a Child
instance.

Regards
Lutz
 
A

Albert Hofkamp

in python, when a class, say Father, has a member that itself is an
instance of another class, say Child, an instance of Father actually
only has a reference to a Child, not the Child object itself, right?

Correct, although I don't rally see why this is important.
because i know that in eiffel they give the programmer the 2 options,
the second being implemented with an additional keyword (expanded) so as
the eiffel documentation says,

"Consider the example of a class covering the notion of car. Many cars
share the same originating_plant , but an engine belongs to just one

You mean inheritance here, as in

class Father(Child):
...

?
car. References represent the modeling relation "knows about";
subobjects, as permitted by expanded types, represent the relation "has
part", also known as aggregation. The key difference is that sharing is
possible in the former case but not in the latter"

Sharing is normally in one direction only, ie from Father to Child,
afaik in both cases (both member-of and inheritance).
Normally, one would write Child without being aware of Father, that is,
Child should be written as a stand-alone, so it may be used in arbitrary
contexts, such as

class Mother(Child):
..
the reason why i'm asking is that i want my Child() instance to know
things about the parent without having to explicitly pass them as
arguments. this is not working :(

You are trying to do something that is contradictionary to the OO idea.
Luckily, that does not mean it is impossible to do.

If the parent and the child class need to share data, you either put the
data in the sub-class (ie Child), or you create a new class that holds
the data where both the parent and the child have access to.

Imho the first solution is preferrable because of a well-defined
ownership of the data.


Albert
 
B

Bruno Desthuilliers

Ali said:
hi all:

in python, when a class, say Father, has a member that itself is an
instance of another class, say Child, an instance of Father actually
only has a reference to a Child, not the Child object itself, right?

I'm not sure I get the point. With Python, you only have symbols that
are bounds to objects.
because i know that in eiffel they give the programmer the 2 options,
the second being implemented with an additional keyword (expanded) so as
the eiffel documentation says,

"Consider the example of a class covering the notion of car. Many cars
share the same originating_plant , but an engine belongs to just one
car. References represent the modeling relation "knows about";
subobjects, as permitted by expanded types, represent the relation "has
part", also known as aggregation. The key difference is that sharing is
possible in the former case but not in the latter"

No such thing in Python. But it comes down to :
1/ an object A is 'shared' by many others B* (composition) :
you instanciate A, and pass it to each B that needs to 'know about' it.

2/ an object A is 'part of' an object B (aggregation) :
B instanciate A, and no one else keeps a reference to A.

the reason why i'm asking is that i want my Child() instance to know
things about the parent without having to explicitly pass them as
arguments.

This seems quite a different problem. AFAICT, the Eiffel mechanism you
mention don't let 'part' objects know anything about the object that
'own' them (I may be wrong since I don't know Eiffel that much, but...).
this is not working :(

I can't see how it could work. A object instance can only know what you
let it know, so unless you pass it a ref to another object, it can't
know nothing about it.
eg code that doesn't work:

class Father:

def __init__(self):
self.a = 'foo'
self.son = Child()

class Child:

def __init__(self):
print f.a
where is this 'f' coming from ?-)
f = Father()
How would you expect the Child *class* to know anything about a symbol
that is yet unbound ?

You have two options :

1/
class Father:
def __init__(self):
self.a = a
self.son = Child(self)

def doIt(self):
self.son.somethingElse()


class Child:
def __init__(self, father):
self.father = father
print self.father.a

def somethingElse(self):
print self.father.a


2/
class Father:
def __init__(self):
self.a = a
self.son = Child(self)

def doIt(self):
self.son.somethingElse(self)


class Child:
def __init__(self, father):
print father.a

def somethingElse(self, father):
print father.a


Note that
- with the first solution, you create a circular reference between
Father and Child instances - but Python now has a real GC that handle
such situations, so this may not be a problem.

- with the second solution, you can pass any other Father-like object to
a Child instance, which may or may not be a problem.

Now there is no "Good" or "Bad" solution, it depends on the problem at hand.

HTH
Bruno
 
A

Ali El Dada

ok thanks, i understood my mistake, now to the solution:


Albert said:
If the parent and the child class need to share data, you either put the
data in the sub-class (ie Child), or you create a new class that holds
the data where both the parent and the child have access to.

well the first solution is not feasible with me because i may have more
classes and subclasses that may need this information (it is like a
dictionary that has some global information, e.g. about the environment)

so do you advise me to take the second solution, creating a class called
Global that any other class can access?? as in: (not tested)

class Global:
user_home = os.environ['HOME']
my_app_data = 'C:\\Program Files\\MyApp'

class AnyClass:
self.user_home = Global.user_home
 
L

Lutz Horn

Hi,

* Ali El Dada said:
well the first solution is not feasible with me because i may have
more classes and subclasses that may need this information (it is
like a dictionary that has some global information, e.g. about the
environment)

What's the problem with passing the context to every instance of a
subclass? It's only a parameter in a constructor or the call of a
method like setContext().
so do you advise me to take the second solution, creating a class
called Global that any other class can access?? as in: (not
tested)

class Global:
user_home = os.environ['HOME']
my_app_data = 'C:\\Program Files\\MyApp'

class AnyClass:
self.user_home = Global.user_home

No, don't use global data.

Lutz
 
A

Ali El Dada

ok that settles everything.. thanks a million!!!


Regards,
Ali Dada


Lutz said:
Hi,

* Ali El Dada said:
well the first solution is not feasible with me because i may have
more classes and subclasses that may need this information (it is
like a dictionary that has some global information, e.g. about the
environment)


What's the problem with passing the context to every instance of a
subclass? It's only a parameter in a constructor or the call of a
method like setContext().

so do you advise me to take the second solution, creating a class
called Global that any other class can access?? as in: (not
tested)

class Global:
user_home = os.environ['HOME']
my_app_data = 'C:\\Program Files\\MyApp'

class AnyClass:
self.user_home = Global.user_home


No, don't use global data.

Lutz
 
T

Terry Reedy

Ali El Dada said:
in python, when a class, say Father, has a member that itself is an
instance of another class, say Child, an instance of Father actually
only has a reference to a Child, not the Child
object itself, right?

Good question. As you defined the difference by
quoting from Eiffel, yes. The association
relating names and collection slots to objects is
many to one. A given object can be associated
with (referenced by) multiple names, lists, dicts,
and instances. This is essential to Python's
operation. If you want to restrict the
association to be one to one (as in engine belongs
to only one car), you must exert the discipline
yourself. You can facilitate this by making the
restricted class private to a module or another
class. I have never heard of this being a
problem.
eg code that doesn't work:
class Father:
def __init__(self):
self.a = 'foo'
self.son = Child()

class Child:
def __init__(self):
print f.a

f = Father()

Put on your Python interpreter hat and try to
execute this. Father calls Father.__init__ calls
Child calls Child.__init__ tries to access object
named f, but there is no such object because the
calls have not returned and hence the binding of
global f to Father instance has not yet occurred
and hence you get a NameError.
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in __init__
File "<stdin>", line 3, in __init__
NameError: global name 'f' is not defined

(Please, when you post code that 'does not work',
cut and paste the error traceback as above.)

If you want to create a circular reference between
Father and Child, pass the Father instance to the
Child initialization.

class Father:
def __init__(self):
self.a = 'foo'
self.son = Child(self)

class Child:
def __init__(self, father):
self.father = father
print father.a
foo

Terry J. Reedy
 
J

John Landahl

Ali El Dada said:
so do you advise me to take the second solution, creating a class called
Global that any other class can access?? as in: (not tested)

class Global:
user_home = os.environ['HOME']
my_app_data = 'C:\\Program Files\\MyApp'

class AnyClass:
self.user_home = Global.user_home

Take a look at PEAK, the Python Enterprise Application Kit
(http://peak.telecommunity.com/). It has advanced configuration and
binding capabilities that make this sort of thing incredibly simple
(and which provide far more power and flexibility), without needing to
resort to singletons like your Global class.

Using PEAK your AnyClass might look like this:

from peak.api import binding, PropertyName
class AnyClass(binding.Component):
user_home = binding.Obtain(PropertyName('environ.HOME'))
app_data = binding.Obtain(PropertyName('myapp.data'))

binding.Obtain allows you to locate and "bind to" an object that's
been created elsewhere in the program. Objects are located through
"configuration keys" -- in this case dotted "property names" are used,
though there are other choices which provide even more flexibility.
Properties provide a simple way to organize data hierarchically (e.g.
'myapp.foo.bar.whatever') and which have a direct tie-in to external
..ini config files. "environ.*" provides a simple way to lookup
environment variables, and "myapp.data" could be specified in a config
file like so:

[myapp]
data = 'C:\\Program Files\\MyApp'

There's a great introductory tutorial on the PEAK DevCenter wiki:

http://peak.telecommunity.com/DevCenter/IntroToPeak

It walks you through creating simple applications with these features,
and moves on to more advanced PEAK features that you might also find
useful.
 

Ask a Question

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

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

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
474,172
Messages
2,570,934
Members
47,478
Latest member
ReginaldVi

Latest Threads

Top