How to build Hierarchies of dict's? (Prototypes in Python?)

C

Charles D Hixson

I'm sure I've read before about how to construct prototypes in Python,
but I haven't been able to track it down (or figure it out).

What I basically want is a kind of class that has both class and
instance level dict variables, such that descendant classes
automatically create their own class and instance level dict variables.
The idea is that if a member of this hierarchy looks up something in
it's local dict, and doesn't find it, it then looks in the class dict,
and if not there it looks in its ancestral dict's. This is rather like
what Python does at compile time, but I want to do it at run time.

I'm sure I've seen how to do it...but have no idea where, or what it was
called, or when (probably around the time Prothon was being discussed,
as I have the idea of prototype associated with it for no clear reason).
 
L

Larry Bates

Charles said:
I'm sure I've read before about how to construct prototypes in Python,
but I haven't been able to track it down (or figure it out).

What I basically want is a kind of class that has both class and
instance level dict variables, such that descendant classes
automatically create their own class and instance level dict variables.
The idea is that if a member of this hierarchy looks up something in
it's local dict, and doesn't find it, it then looks in the class dict,
and if not there it looks in its ancestral dict's. This is rather like
what Python does at compile time, but I want to do it at run time.

I'm sure I've seen how to do it...but have no idea where, or what it was
called, or when (probably around the time Prothon was being discussed,
as I have the idea of prototype associated with it for no clear reason).

What you describe is exactly how Zope works so you might want to spend
some time looking at it.

http://www.zope.org

-Larry
 
C

Charles D Hixson

Larry said:
What you describe is exactly how Zope works so you might want to spend
some time looking at it.

http://www.zope.org

-Larry
Thanks for the suggestion, and I'll do that if I must, but Zope is
pretty heavy to drag into something for just one function, and I don't
really see any use for most parts of it in what I'm doing. And that's a
LOT of code to wade through for one technique.
 
T

Toby

Charles said:
What I basically want is a kind of class that has both class and
instance level dict variables, such that descendant classes
automatically create their own class and instance level dict variables.
The idea is that if a member of this hierarchy looks up something in
it's local dict, and doesn't find it, it then looks in the class dict,
and if not there it looks in its ancestral dict's. This is rather like
what Python does at compile time, but I want to do it at run time.

I don't understand, Python already does it at runtime:

class A:
A_class_var = 1

class B(A):
B_class_var = 2
def __init__(self):
self.B_inst_var = 3
4

Can you post a ">>>"-script of what you would like your classes to do?


Toby
 
C

Charles D Hixson

Toby said:
I don't understand, Python already does it at runtime:

class A:
A_class_var = 1

class B(A):
B_class_var = 2
def __init__(self):
self.B_inst_var = 3


4

Can you post a ">>>"-script of what you would like your classes to do?


Toby
Sorry, the "script" hasn't been written. But Python apparently *won't*
(automatically) do what I want, which is create a class whose
sub-classes automatically have unique class variables of a determined
form such that I can do a hierarchical search through them. (I could
plausibly handle this for the instance case but "class variables are
static", so it looks like I can't do it for class variables in a
straightforward manner. This looks like it's going to demand a factory
method, or some alternate approach. (Not sure yet which I'll choose.)

What I'm looking for is a reasonable way to implement what Marvin Minsky
calls Panologies. These are "objects" (my term) with sufficient local
intelligence to try alternative models of a situation until they find
one that's appropriate. E.g., is this being operated on as a physical
transaction or a social transaction. (Yes, it is physically happening,
and it's taking place in physical space, but different models yield
different analyses of what's happening. Which is appropriate for the
situation currently being evaluated?)

Well, I'm not trying to handle all that, merely to create a simple model
of what a panology *IS*. So each Panology object will need a list of
delegatees to handle the operations, and a list of indexes to assist it
in evaluating which delegatee to use. If it doesn't find it locally, it
will need to search through the situational context and these should be
maintained at both the class and instance levels by it's ancestors. The
base class should have a method that manages the searching, and the
finding of delegatees (models) based around the indexing keys.

This will take a bit of work, but if I can manage it, it should be
rather interesting. It could also be used to test some of Minsky's
ideas...or not, because what I'm thinking of it different from exactly
what he's proposing.

E.g., after I figure out how to build the basic structure, I'm going to
need to figure out how to determine the appropriate model. This may be
a harder problem.

P.S.: What I really expect is that by the time I get this solved,
somebody else will already have a solution. (It's happened before. I
had the "idea" of an "intelligent spam filter" before spambayes was
built...but I was much too slow at the implementation. MUCH! (I spend
too much time dreaming and not enough time programming.)

P.P.S.: This isn't all loss. I'm expecting that eventually I'll start
running into performance problems, and at that point it would be
necessary to start translating into a native-compiler language.
 
G

Gabriel Genellina

En Sat, 24 Feb 2007 21:29:13 -0300, Charles D Hixson
Sorry, the "script" hasn't been written. But Python apparently *won't*
(automatically) do what I want, which is create a class whose
sub-classes automatically have unique class variables of a determined
form such that I can do a hierarchical search through them. (I could
plausibly handle this for the instance case but "class variables are
static", so it looks like I can't do it for class variables in a
straightforward manner. This looks like it's going to demand a factory
method, or some alternate approach. (Not sure yet which I'll choose.)

"Class variables are static" until you assign to them a new value, then
become instance (normal) attributes.

class A:
x = 1

a = A()
a.x # prints 1
a.x = 100
a.x # prints 100
A.x # still 1
b = A()
b.x # still 1
What I'm looking for is a reasonable way to implement what Marvin Minsky
calls Panologies. These are "objects" (my term) with sufficient local
intelligence to try alternative models of a situation until they find
one that's appropriate. E.g., is this being operated on as a physical
transaction or a social transaction. (Yes, it is physically happening,
and it's taking place in physical space, but different models yield
different analyses of what's happening. Which is appropriate for the
situation currently being evaluated?)

You may be interested on Acquisition, a concept from Zope2. Objects not
only have behavior by nature (inheritance) but nurture (acquisition).
*Where* an object is contained (or, *how* you reach to it), determines its
behavior as well as *what* it is.
P.P.S.: This isn't all loss. I'm expecting that eventually I'll start
running into performance problems, and at that point it would be
necessary to start translating into a native-compiler language.

Your design seems to be too dynamic to be feasible on a more static
language.
 
T

Toby

Charles said:
a class whose sub-classes automatically have unique class variables of
a determined form such that I can do a hierarchical search through them

Something like this?
(scroll down to see the results)


# --- begin ---

class AttrSearch(object):
@classmethod
def getclassattrset(cls, name):
s = set()
if name in cls.__dict__:
s.add((cls.__name__, cls.__dict__[name]))
for base in cls.__bases__:
try:
s.update(base.getclassattrset(name))
except AttributeError:
pass
return s

def getattrset(self, name):
s = set()
try:
s.add((None, self.__dict__[name]))
except KeyError:
pass
s.update(self.__class__.getclassattrset(name))
return s

def __getattribute__(self, name):
if name.startswith('__'): #XXX not pretty
return object.__getattribute__(self, name)
found = AttrSearch.getattrset(self, name)
print 'Looking for "%s" in a %s instance, found %d candidates:' \
% (name, self.__class__.__name__, len(found))
print '\n'.join([ ' %-4s %s' % x for x in found ])
print '(now choose wisely what to return)'

class A(AttrSearch):
a = 1

class B(A):
a = 2

class C(A):
a = 3

class D(B, C):
a = 4


D().a

# --- end ---


Results:

Looking for "a" in a D instance, found 4 candidates:
A 1
B 2
C 3
D 4
(now choose wisely what to return)


Toby
 
T

Toby

Charles said:
I want to access the values via instances of the class, so your D().a
approach isn't suitable. More like: "t = D(); t[a]"

Well, D() is an instance of D, so D().a is the same as t = D(); t.a
In fact the various "a" attributes I'm accessing are class attributes of
the various classes, just as you asked.

If you'd rather use t[a], then things are simpler, because you won't
need to override __getattribute__, with all the ugliness that comes with
it: __getitem__ will suffice.

Your approach uses techniques that I'm going to need to study
carefully before I can hope to understand them.

Don't worry, here's a heavily commented version, just because it's
sunday and I have some free time ;-)


# inheriting from object so that we can use __getattribute__
# see http://www.python.org/download/releases/2.2.3/descrintro/
class AttrSearch(object):
'''Base class that customizes attribute access in all of its derived
classes, choosing between all the candidates in a custom way.'''


@classmethod
def getclassattrset(cls, name):
'''Class method (= polymorphic static method) that collects a set
of the attributes with a given name from itself and from all its
base classes (determined at runtime.)

The only argument is the name of the attribute to look up; the
return value is a list of (class_name, attribute_value) listing all
the candidates found.'''

# note: the first parameter 'cls' is the class of the runtime object
# on which this class method is called, much like 'self' is the
# object instance in instance methods
#
# notice: this method is defined on class AttrSearch, but if I call
# it on B (subclass of AttrSearch), then 'cls' is class B!

s = set() # a set is an unordered list without duplicates

try:
# __dict__ is the internal dictionary which holds all of a class
# or of an instance's attributes

# creating a tuple with the name of the runtime class 'cls'
# and the value of cls's attribute named name, and adding the
# tuple to the set (unless an equal tuple is already there)
s.add((cls.__name__, cls.__dict__[name]))
except KeyError:
# ...unless the class cls has no such attribute
pass

# for every base class, from which the runtime class inherits:
for base in cls.__bases__:
try:
# call this same method on them and add their results to the set
s.update(base.getclassattrset(name))
except AttributeError:
# except for the base classes which don't implement this method
# (for example the class object)
pass

return s # returning the collected set


def getattrset(self, name):
'''Instance method that collects a set of the attributes with a
given name from itself, from its class and from all the base classes.

The only argument is the name of the attribute to look up; the
return value is a list of (class_name, attribute_value) listing all
the candidates found. In case the attribute is also found in the
object itself, element 0 of the tuple is set to null.'''

# saving references to a couple of attributes we need to access
# directly, bypassing all this machinery; to achieve it, we
# explicitly call object's implementation of __getattribute__

self_dict = object.__getattribute__(self, '__dict__')
self_class = object.__getattribute__(self, '__class__')

s = set()

try:
# adding to the set the attribute named name in this very intance,
# if it exists, with None in place of the class name
s.add((None, self_dict[name]))
except KeyError:
# unless the instance doesn't have an attribute named name
pass

# addig to the set all the class attributes named name, from this
# object's class and all its base classes
s.update(self_class.getclassattrset(name))

return s


def __getattribute__(self, name):
'''Customized version of attribute fetching, that uses getattrset
(and thus getclassattrset) to get a list of all the attributes named
name before choosing which one to return.'''

# saving references to the attributes we need to access directly
self_class = object.__getattribute__(self, '__class__')

# calling AttrSearch's getattrset to do the dirty work
found = AttrSearch.getattrset(self, name)

# here is where you should examine 'found' and choose what to
# return; I only print what is available and return None
print 'Looking for "%s" in a %s instance, found %d candidates:' \
% (name, self_class.__name__, len(found))
print ' class value'
print ' ===== ====='
print '\n'.join([ " %-6s '%s'" % x for x in found ])
print '(now choose wisely what to return)'

return None


# example use of AttrSearch in a class hierarchy:

class A(AttrSearch):
a = 'attribute "a" of class A'

class B(A):
a = 'attribute "a" of class B'

class C(A):
a = 'attribute "a" of class C'

class D(B, C):
a = 'attribute "a" of class D'

t = D()
t.a = 'attribute "a" of instance t'

# --- end ---

Now if you ask for t.a, for example in a print statement, you get None,
but not before the following lines are printed to stdout:


Looking for "a" in a D instance, found 5 candidates:
class value
===== =====
D 'attribute "a" of class D'
B 'attribute "a" of class B'
A 'attribute "a" of class A'
None 'attribute "a" of instance t'
C 'attribute "a" of class C'
(now choose wisely what to return)



HTH
Toby

PS: I couldn't make out what you meant with your code... I fear it's
because of the hideous formatting :)
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top