Can dictionary values access their keys?

Discussion in 'Python' started by Matthew Thorley, Apr 8, 2005.

  1. This may be a very rudimentary question, but here goes:

    If I have a simple dictionary, where the value is a class or function,
    is there an interface through which it can discover what its key is?
    Similar to index() for list.

    For a list, assuming I new what the parent list was I could do something
    like this.

    >>> class child:

    .... def get_parent_index(self, parent):
    .... return parent.index(self)
    ....
    >>> a = child()
    >>> l = [a]
    >>> b = l[0]
    >>> b.get_parent_index(a)
    >>> b.get_parent_index(l)

    0

    Is there a way to do something like that with dicts?


    On a similar note, if one object is part of another, is there a way for
    the 'child' obj to discover what/who the 'parent' object is? That way
    parent does not have to be explicityly passed to get_parent_index?

    The idea is like this:

    >>> class child:

    .... def get_parent_index(self):
    parent = self.magic_parent_discovery()
    .... return parent.index(self)
    ....



    Thanks much
    --
    Matthew
     
    Matthew Thorley, Apr 8, 2005
    #1
    1. Advertising

  2. >
    > Is there a way to do something like that with dicts?


    Not without searching the dict's items through, or keeping a additional
    mapping between values and keys.

    >
    > On a similar note, if one object is part of another, is there a way for
    > the 'child' obj to discover what/who the 'parent' object is? That way
    > parent does not have to be explicityly passed to get_parent_index?


    No.
    --
    Regards,

    Diez B. Roggisch
     
    Diez B. Roggisch, Apr 8, 2005
    #2
    1. Advertising

  3. Can you please elaborate on this?
    -Matthew

    Diez B. Roggisch wrote:
    >>keeping a additional mapping between values and keys.

    >
     
    Matthew Thorley, Apr 8, 2005
    #3
  4. Hello!

    > If I have a simple dictionary, where the value is a class or function,
    > is there an interface through which it can discover what its key is?


    The key of a value may not be unique, so you can also get a tupe of
    keys, like dict(a=1, b=1), the key's of 1 are a and b.

    For unique values, I did something like that couple of weeks ago, the
    thing you would need is the getKey thing, it's fast, but needs much
    memory for big structures becouse I use two dicts.
    If speed does not matter:

    class ReverseDict(dict):
    def get_keys(self, value):
    keys = []
    for k, v in self.items():
    if v == value: keys.append(k)
    return keys

    class UniqueReverseDict(dict):
    """
    A dictionary that can resolute reverse: A object to a key. Both, the Key and
    the Value must be unique.
    """

    def __init__(self, **kws):
    super(UniqueReverseDict, self).__init__(kws)
    self.__reverse = {}

    def __setitem__(self, k, v):
    super(UniqueReverseDict, self).__setitem__(k, v)
    self.__reverse[v] = k

    def __update_reverse(self):
    self.__reverse.clear()
    for k, v in self.items():
    self.__reverse[v] == k

    def has_value(self, v):
    return self.__reverse.has_key(v)

    def __delitem__(self, k):
    self.__reverse[self[k]]
    super(UniqueReverseDict, self).__delitem__(k)

    def clear(self):
    self.__reverse.clear()
    super(UniqueReverseDict, self).clear()

    def copy(self):
    return UniqueReverseDict(self)

    def pop(self, k):
    del self.__reverse[self[k]]
    return self.pop(k)

    def popitem(self, **kws):
    raise 'AxsPy.Misc.Structures.UniqueReverseDict', \
    'NotImplemented'

    def setdefault(self, **kws):
    raise 'AxsPy.Misc.Structures.UniqueReverseDict', \
    'NotImplemented'

    def update(self, **kws):
    super(UniqueReverseDict, self).update(**kws)
    self.__update_reverse()

    def getKey(self, v): return self.__reverse[v]

    Lg,
    AXEL
    --
    "Aber naja, ich bin eher der Forentyp." Wolfibolfi's outing in
    http://www.informatik-forum.at/showpost.php?p=206342&postcount=10
     
    Axel Straschil, Apr 8, 2005
    #4
  5. Matthew Thorley wrote:

    > Can you please elaborate on this?


    Eh, just have two dicts that are the inverse of each other. You could do
    that by subclassinc dict:

    class mydict(dict):
    def __init__(self):
    self.__inverse_mapping = {}

    def __setitem__(self, key, value):
    dict.__setitem__(key, value)
    self.__inverse_mapping[value] = key


    def key4value(self, v):
    return self.__inverse_mapping[v]


    But of course this only works if your mapping is bijective. Consider this:

    d = mydict()
    d[10] = 20
    print d.key4value(20)
    d[15] = 20
    print d.key4value(20)

    This will of course not give you (10,15), but 15 only - the last mapping
    overwrites earlier ones. And beware of non-hashable objects like lists or
    dicts themselves, they aren't working as keys. So this produces an error:

    d[100] = [1,2,3,4]
    TypeError: list objects are unhashable





    --
    Regards,

    Diez B. Roggisch
     
    Diez B. Roggisch, Apr 8, 2005
    #5
  6. Axel Straschil wrote:
    >
    > For unique values, I did something like that couple of weeks ago, the
    > thing you would need is the getKey thing, it's fast, but needs much
    > memory for big structures becouse I use two dicts.


    Thanks for the tip, I may give that a try. I'll be interested to see
    what kind of speed penalty I pay. The data I am using has multiples
    dictionaries with maybe a thousand entries each. But each entry is an
    object containing a history of data with perhaps hundreds or even
    thousands more entries. So we're talking about maybe a million+ total
    nested key:values. I don't know if that counts as large or not. I can't
    even guess how much k memory that is.

    I must say I am *very* suprised that python does not have a way to look
    up what key is pointing to a given object--without scanning the whole
    list that is. Is that what list.index() does under-the-hood? I mean is
    list.index(y) just the same as

    itemnum = 0
    for item in list:
    if y == item:
    return itemnum
    else:
    itemnum = itemnum+1


    I think I am going to have to reevaluate my system design... grrr.

    thanks
    --
    Matthew
     
    Matthew Thorley, Apr 8, 2005
    #6
  7. Matthew Thorley

    Steve Holden Guest

    Matthew Thorley wrote:
    > This may be a very rudimentary question, but here goes:
    >
    > If I have a simple dictionary, where the value is a class or function,
    > is there an interface through which it can discover what its key is?
    > Similar to index() for list.
    >

    No, because mapping types (of which dict is the canonical example) don;t
    guarantee uniqueness of values. In other words, there can be several
    keys mapping to the same value.

    You would therefore need to know how to handle such cases - would you
    want to return an arbitrary one of those keys, or a list of them all?

    A standard dict doesn't keep any record of the order in which keys were
    added, so there are some things you *can't* do, like return "the first
    key added with a given value".

    > For a list, assuming I new what the parent list was I could do something
    > like this.
    >
    >
    >>>>class child:

    >
    > ... def get_parent_index(self, parent):
    > ... return parent.index(self)
    > ...
    >
    >>>>a = child()
    >>>>l = [a]
    >>>>b = l[0]
    >>>>b.get_parent_index(a)
    >>>>b.get_parent_index(l)

    >
    > 0
    >
    > Is there a way to do something like that with dicts?
    >

    So you know about the .index() and .find() methods, and of course since
    there is no guarantee that a value appears only once in the list they
    disambiguate by returning the lowest index containing the value.

    A simple way to do what you appear to want would be:

    def get_parent_index(self, parent):
    for k, v in parent.items():
    if v == self:
    return k

    This would return None if the required item wasn't found in the dict parent.
    >
    > On a similar note, if one object is part of another, is there a way for
    > the 'child' obj to discover what/who the 'parent' object is? That way
    > parent does not have to be explicityly passed to get_parent_index?
    >

    This is like asking if you can find the "name" of an object. The fact is
    that a single object can be bound to many variables. Suppose I write:

    lst = [1, 2, 3]

    does that mean that the "name" of 2 is lst[1]? No - 2 is just a value
    that happens to be bound to that list element (among other things).

    If I then write

    otherlst = lst
    otherlst[1' = "two"

    you will find that lst[1] is also now bound to "two" because lst and
    otherlst are in fact references tot he same list object, so changing one
    also changes the other. Given that, what is the "name" of that list?

    > The idea is like this:
    >
    >
    >>>>class child:

    >
    > ... def get_parent_index(self):
    > parent = self.magic_parent_discovery()
    > ... return parent.index(self)
    > ...
    >


    Given a set of objects and a known attribute or set of attributes for
    those objects that might be references to a specific search target you
    can perform the magic you want, but a generic search for "any reference
    to the search target", while not impossible (using Python's excellent
    introspection facilities) is way beyond what most people would consider
    practical. Obviously the garbage collector has to solve this problem,
    but you *really* don't want to be doing this stuff in Python unless you
    absolutely *must*.

    regards
    Steve
    --
    Steve Holden +1 703 861 4237 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/
     
    Steve Holden, Apr 8, 2005
    #7
  8. Matthew Thorley wrote:
    > This may be a very rudimentary question, but here goes:

    From your questions, I believe you are not thinking of values as
    being distinct from the names and data structures that refer to them.

    What is the parent of 23 in the following expression?

    1 + 11 * 2

    If you know that, what is the parent of 293 in the same expression?

    > If I have a simple dictionary, where the value is a class or function,
    > is there an interface through which it can discover what its key is?
    > Similar to index() for list.


    def keyfor(dictionary, element):
    for key, value in dictionary.iteritems():
    if value == element: # value is element if identity quest
    return key
    raise ValueError, element

    > On a similar note, if one object is part of another,

    This is the idea you have wrong. In C, C++, Java, and Fortran you
    might have objects part of other objects, but in Python objects refer
    to each other.

    How about this:

    class Holder(object): pass

    v = [1 + 11 * 2]
    w = [1, v, 3]
    d = {1: v}
    o = Holder()
    o.x = v

    What is the parent of v?

    Or even worse:

    v = [1]
    v[0] = v

    What is the parent of v now?

    --Scott David Daniels
     
    Scott David Daniels, Apr 8, 2005
    #8
  9. Hello!

    > thousands more entries. So we're talking about maybe a million+ total
    > nested key:values. I don't know if that counts as large or not. I can't
    > even guess how much k memory that is.


    Mhh, maybe you should use a SQL-Database ;-)

    Lg,
    AXEL.
    --
    "Aber naja, ich bin eher der Forentyp." Wolfibolfi's outing in
    http://www.informatik-forum.at/showpost.php?p=206342&postcount=10
     
    Axel Straschil, Apr 8, 2005
    #9
  10. Steve Holden wrote:
    while not impossible (using Python's excellent
    > introspection facilities) is way beyond what most people would consider
    > practical. Obviously the garbage collector has to solve this problem,
    > but you *really* don't want to be doing this stuff in Python unless you
    > absolutely *must*.
    >
    > regards
    > Steve



    Thanks very much for the detailed reply. Let me explain in a little more
    detail what I am doing, and perhaps you could let me know if I am going
    about it the wrong way.


    I am creating an object database to store information about network
    devices, e.g. switches and routers.

    At the top level there are device objects, every device object contains
    a mib object--and other various properties--where the actual data is
    stored. The mib object is a dicitionary--or at least subclasses
    dictionary--where the key is the oid (a unique string) and the value is
    a special object called Datapoint. Datapoints come in two types Static
    and Dynamic, and every Datapoint is unique.

    So a simple structure looks something like this:

    Device1
    Mib1
    {'1.3.6.1':Datapoint-x1,
    '1.3.6.2':Datapoint-y1,
    '1.1.5.4':Datapoint-z1,
    '1.2.7.3':Datapoint-q1}

    Device2
    Mib2
    {'1.3.6.1':Datapoint-x2,
    '1.3.6.2':Datapoint-y2,
    '1.1.5.4':Datapoint-z2,
    '1.2.7.3':Datapoint-q2}

    In the example Datapoint-xx should be read as, some unique data point in
    memory.

    The key in the Mib object is important because it is used by the
    Datapoint is points to to look up its current value on the given device,
    which is why I asked the two questions.

    In my program I use snmp to look up values on network devices. i.e. 'Go
    find the value of 1.3.6.1 from device1.' I want to be able to say
    something like Device1.Mib['1.3.6.1].update(), and the correct Datapoint
    discovers its key (oid) and parent device, then executes an snmp query
    that looks something like this snmpget(keyThatPointsToSelf,
    parentObj.ipAddress, parentObj.paramx)

    I know of course I could keep all this in a relational database and do a
    bunch of queries, but that would really suck! and I would have to track
    all the Devices and oids my self. What I really want is smart objects
    that think for me--thats what computers are for, right? ;)

    I thought my design was a wonderfuly beautiful use of python an oop, but
    perhaps I am mistaken and there is a much more pragmatic way to get the
    job done. In the end preformance doesn't matter a lot. The front end
    will be web based, so if the db can process faster than http/javascript
    and user Bob who has to mouse, then everything will be fine.

    Let me know what you think
    Thanks much
    --Matthew
     
    Matthew Thorley, Apr 8, 2005
    #10
  11. Scott David Daniels wrote:
    > Matthew Thorley wrote:
    >
    >> This may be a very rudimentary question, but here goes:

    >
    > From your questions, I believe you are not thinking of values as
    > being distinct from the names and data structures that refer to them.
    >
    > What is the parent of 23 in the following expression?
    >
    > 1 + 11 * 2
    >
    > If you know that, what is the parent of 293 in the same expression?
    >
    >> If I have a simple dictionary, where the value is a class or function,
    >> is there an interface through which it can discover what its key is?
    >> Similar to index() for list.

    >
    >
    > def keyfor(dictionary, element):
    > for key, value in dictionary.iteritems():
    > if value == element: # value is element if identity quest
    > return key
    > raise ValueError, element
    >
    >> On a similar note, if one object is part of another,

    >
    > This is the idea you have wrong. In C, C++, Java, and Fortran you
    > might have objects part of other objects, but in Python objects refer
    > to each other.
    >
    > How about this:
    >
    > class Holder(object): pass
    >
    > v = [1 + 11 * 2]
    > w = [1, v, 3]
    > d = {1: v}
    > o = Holder()
    > o.x = v
    >
    > What is the parent of v?
    >
    > Or even worse:
    >
    > v = [1]
    > v[0] = v
    >
    > What is the parent of v now?
    >
    > --Scott David Daniels
    >


    I see what your saying, but I my situation the values of the dictionary
    are unique objects created by a parent object. Sorry :(, I didn't
    explain that very well in my first post.

    When the 'root object' is 'global' I see what your saying, but when

    class A:
    def __init__(self, container):
    self.container=container

    class B(dict):
    def magice_get_parent(self):
    ...

    class special_value():
    def __init__(self, val):
    self.val = val

    def magic_get_key(self):
    ...

    parent = A(B)
    parent.container[x] = special_value(1)
    parent.container[y] = special_value(2)
    parent.container[z] = special_value(1)


    In this example, in my mind, the following should happen, and in theory
    using introspecition, actualy possible.

    child = parent.container
    D.magic_get_parent() #returns parent


    value1 = parent.container[x]
    value2 = parent.container[y]
    value3 = parent.container[z]

    value1.magic_get_key() #returns x
    value2.magic_get_key() #returns y
    value3.magic_get_key() #returns z

    Let me know if I'm nutz!
    --Matthew
     
    Matthew Thorley, Apr 8, 2005
    #11
  12. Matthew Thorley

    Steve Holden Guest

    Matthew Thorley wrote:
    > Steve Holden wrote:
    > while not impossible (using Python's excellent
    >
    >>introspection facilities) is way beyond what most people would consider
    >>practical. Obviously the garbage collector has to solve this problem,
    >>but you *really* don't want to be doing this stuff in Python unless you
    >>absolutely *must*.
    >>
    >>regards
    >> Steve

    >
    >
    >
    > Thanks very much for the detailed reply. Let me explain in a little more
    > detail what I am doing, and perhaps you could let me know if I am going
    > about it the wrong way.
    >
    >
    > I am creating an object database to store information about network
    > devices, e.g. switches and routers.
    >
    > At the top level there are device objects, every device object contains
    > a mib object--and other various properties--where the actual data is
    > stored. The mib object is a dicitionary--or at least subclasses
    > dictionary--where the key is the oid (a unique string) and the value is
    > a special object called Datapoint. Datapoints come in two types Static
    > and Dynamic, and every Datapoint is unique.
    >
    > So a simple structure looks something like this:
    >
    > Device1
    > Mib1
    > {'1.3.6.1':Datapoint-x1,
    > '1.3.6.2':Datapoint-y1,
    > '1.1.5.4':Datapoint-z1,
    > '1.2.7.3':Datapoint-q1}
    >
    > Device2
    > Mib2
    > {'1.3.6.1':Datapoint-x2,
    > '1.3.6.2':Datapoint-y2,
    > '1.1.5.4':Datapoint-z2,
    > '1.2.7.3':Datapoint-q2}
    >
    > In the example Datapoint-xx should be read as, some unique data point in
    > memory.
    >
    > The key in the Mib object is important because it is used by the
    > Datapoint is points to to look up its current value on the given device,
    > which is why I asked the two questions.
    >
    > In my program I use snmp to look up values on network devices. i.e. 'Go
    > find the value of 1.3.6.1 from device1.' I want to be able to say
    > something like Device1.Mib['1.3.6.1].update(), and the correct Datapoint
    > discovers its key (oid) and parent device, then executes an snmp query
    > that looks something like this snmpget(keyThatPointsToSelf,
    > parentObj.ipAddress, parentObj.paramx)
    >
    > I know of course I could keep all this in a relational database and do a
    > bunch of queries, but that would really suck! and I would have to track
    > all the Devices and oids my self. What I really want is smart objects
    > that think for me--thats what computers are for, right? ;)
    >
    > I thought my design was a wonderfuly beautiful use of python an oop, but
    > perhaps I am mistaken and there is a much more pragmatic way to get the
    > job done. In the end preformance doesn't matter a lot. The front end
    > will be web based, so if the db can process faster than http/javascript
    > and user Bob who has to mouse, then everything will be fine.
    >
    > Let me know what you think
    > Thanks much
    > --Matthew


    I think that since each Datapoint appears to be unique, the simplest
    thing to do is to include a reference to the parent object as an
    attribute of the datapoint. Presumably when you create the Datapoint you
    already know which Device and Mib it's going to be stored in, so why
    make work for yourself when you can trade a little storage and make the
    whole thing easy?

    You might also be interested to know that the Python Software Foundation
    funded the development of a Python package to support SNMP as a part of
    its first round of grant funding last year, so there's at least one
    other person working on this stuff!

    http://www.python.org/psf/grants/

    regards
    Steve
    --
    Steve Holden +1 703 861 4237 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/
     
    Steve Holden, Apr 8, 2005
    #12
  13. Steve Holden wrote:

    > I think that since each Datapoint appears to be unique, the simplest
    > thing to do is to include a reference to the parent object as an
    > attribute of the datapoint. Presumably when you create the Datapoint you
    > already know which Device and Mib it's going to be stored in, so why
    > make work for yourself when you can trade a little storage and make the
    > whole thing easy?
    >


    I'll give that a shot and see how it goes. It makes sense, the parent
    objects create the child objects, so they could very easily set the
    apropriate parameter.

    On the other hand, the introspecitve stuff is cool! When you say "make
    more work for yourself" are you talking about 400 lines of code or 50.
    Further, is there much processing required to do the magic? When python
    do introspective magic, is it memory intensive? by that I mean does it
    have to make copies of the objects to do the look-ups?

    I don't mind copying the info like you suggest, but if the extra work
    won't take more than a day or two, (or maybe even a week if its fun) I'd
    like to do the introspection so that 1: I know how, 2: I can say that I
    did ;)

    Is there any kind of documentaion, (refference, article, blog-post,
    tutorial), that explains introspection in useful detail, or at least
    enough to get me started?

    > You might also be interested to know that the Python Software Foundation
    > funded the development of a Python package to support SNMP as a part of
    > its first round of grant funding last year, so there's at least one
    > other person working on this stuff!
    >

    I did see that and I was quite pleased! :) I am currently using the
    authors 'old' pysnmp which gets me by, but I am very excited to try out
    the new version when it is ready.


    Thanks again, for the reply and for the grant to pysnmp!

    -Matthew
     
    Matthew Thorley, Apr 8, 2005
    #13
  14. Matthew Thorley

    Max M Guest

    Max M, Apr 8, 2005
    #14
  15. Matthew Thorley

    Steve Holden Guest

    Matthew Thorley wrote:
    > Steve Holden wrote:
    >
    >
    >>I think that since each Datapoint appears to be unique, the simplest
    >>thing to do is to include a reference to the parent object as an
    >>attribute of the datapoint. Presumably when you create the Datapoint you
    >>already know which Device and Mib it's going to be stored in, so why
    >>make work for yourself when you can trade a little storage and make the
    >>whole thing easy?
    >>

    >
    >
    > I'll give that a shot and see how it goes. It makes sense, the parent
    > objects create the child objects, so they could very easily set the
    > apropriate parameter.
    >

    Indeed, they will probably just need to pass "self" as an argument to
    the child object's creator (it will become an argument to the __init__()
    method). This will be pretty cheap, since the additional attribute will
    be bound to an already-existing value.

    > On the other hand, the introspecitve stuff is cool! When you say "make
    > more work for yourself" are you talking about 400 lines of code or 50.
    > Further, is there much processing required to do the magic? When python
    > do introspective magic, is it memory intensive? by that I mean does it
    > have to make copies of the objects to do the look-ups?
    >

    Frankly I am not sure I see the advantage. You seem to be saying that
    rather than provide each child object with a reference to its parent you
    would rather provide it with a reference to the collection of parent
    objects and let it work out which one it wants. Where's the benefit?

    > I don't mind copying the info like you suggest, but if the extra work
    > won't take more than a day or two, (or maybe even a week if its fun) I'd
    > like to do the introspection so that 1: I know how, 2: I can say that I
    > did ;)
    >

    Basically you'd have to iterate over the list of parent objects,
    checking whether the child object's self appeared as a key in its
    dictionary of children, so there's nothing really magical about it.

    The *real* magic comes about when you are looking for arbitrary
    references to an object, and you have to iterate over the locals() from
    each stack frame, and various other magical bits and pieces.

    There have been posts in the past detailing such magic, so Google will
    find them for you if you are keen to bend your brain.

    > Is there any kind of documentaion, (refference, article, blog-post,
    > tutorial), that explains introspection in useful detail, or at least
    > enough to get me started?
    >

    Whole swathes of stuff already posted n c.l.py, not to mention Patrick
    O'Brien's

    http://www-106.ibm.com/developerworks/library/l-pyint.html

    which has been highly spoken of.
    >
    >>You might also be interested to know that the Python Software Foundation
    >>funded the development of a Python package to support SNMP as a part of
    >>its first round of grant funding last year, so there's at least one
    >>other person working on this stuff!
    >>

    >
    > I did see that and I was quite pleased! :) I am currently using the
    > authors 'old' pysnmp which gets me by, but I am very excited to try out
    > the new version when it is ready.
    >
    >
    > Thanks again, for the reply and for the grant to pysnmp!
    >
    > -Matthew


    Happy to help, but I can't take credit for the grant, since all I did as
    a PSF director was vote affirmatively on the recommendations of Martin
    von Lowis' extremely hard-working grants committee.

    regards
    Steve
    --
    Steve Holden +1 703 861 4237 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/
     
    Steve Holden, Apr 8, 2005
    #15
  16. Steve Holden wrote:

    > Indeed, they will probably just need to pass "self" as an argument to
    > the child object's creator (it will become an argument to the __init__()
    > method). This will be pretty cheap, since the additional attribute will
    > be bound to an already-existing value.
    >
    >> On the other hand, the introspecitve stuff is cool! When you say "make
    >> more work for yourself" are you talking about 400 lines of code or 50.
    >> Further, is there much processing required to do the magic? When python
    >> do introspective magic, is it memory intensive? by that I mean does it
    >> have to make copies of the objects to do the look-ups?
    >>

    > Frankly I am not sure I see the advantage. You seem to be saying that
    > rather than provide each child object with a reference to its parent you
    > would rather provide it with a reference to the collection of parent
    > objects and let it work out which one it wants. Where's the benefit?

    All right then.

    > Happy to help, but I can't take credit for the grant, since all I did as
    > a PSF director was vote affirmatively on the recommendations of Martin
    > von Lowis' extremely hard-working grants committee.


    Thanks to the PSF for the grant!

    -Matthew
     
    Matthew Thorley, Apr 8, 2005
    #16
  17. On Fri, 08 Apr 2005 09:30:25 -0600, Matthew Thorley <> wrote:

    >This may be a very rudimentary question, but here goes:
    >
    >If I have a simple dictionary, where the value is a class or function,
    >is there an interface through which it can discover what its key is?
    >Similar to index() for list.


    You can make a reverse dictionary, if the key:value pairs are unique and
    the values are hashable. But I doubt this is the real solution to your real problem.

    >>> def foo(): pass

    ...
    >>> def bar(): pass

    ...
    >>> dct = dict(fookey=foo, barkey=bar)
    >>> dct

    {'barkey': <function bar at 0x0301410C>, 'fookey': <function foo at 0x03014064>}
    >>> revdict = dict((v,k) for k,v in dct.items())
    >>> revdict[foo]

    'fookey'
    >>> revdict[bar]

    'barkey'
    >>> class Baz(object): pass

    ...
    >>> dct['bazkey'] = Baz
    >>> dct

    {'barkey': <function bar at 0x0301410C>, 'fookey': <function foo at 0x03014064>, 'bazkey': <class '__main__.Baz'>}
    >>> revdict = dict((v,k) for k,v in dct.items())
    >>> revdict[Baz]

    'bazkey'


    But if you had

    d = {'key1':foo, 'key2':foo}

    What would foo's key be?

    >
    >For a list, assuming I new what the parent list was I could do something
    >like this.
    >
    >>>> class child:

    >... def get_parent_index(self, parent):
    >... return parent.index(self)
    >...
    >>>> a = child()
    >>>> l = [a]
    >>>> b = l[0]
    >>>> b.get_parent_index(a)
    >>>> b.get_parent_index(l)

    >0
    >
    >Is there a way to do something like that with dicts?
    >
    >
    >On a similar note, if one object is part of another, is there a way for
    >the 'child' obj to discover what/who the 'parent' object is? That way
    >parent does not have to be explicityly passed to get_parent_index?
    >

    Any number of "parents" can refer to a given obj, so even if you
    have a context where you can search successfully, you may find many "parents"
    -- unless you can guarantee 1:1 as in the dct/revdict example above.

    >The idea is like this:
    >
    >>>> class child:

    >... def get_parent_index(self):
    > parent = self.magic_parent_discovery()
    >... return parent.index(self)
    >...
    >

    I would suggest thinking about defining a class for the graph you are concerned with
    and giving it methods to add children to nodes, and automatically maintain the
    parent references as you walk your graph and add or delete nodes. Then you should
    easily be able to define more methods to get various info as you may want.
    Properties may interest you too, giving you a way to convert plain object attributes
    to dynamically computed attributes without chaninging the code that refers to the attribute.

    Unless you have a huge graph, I wouldn't worry about the space. If you bump into
    limitations, try __slots__ for node attributes. But if you know now that it's going
    to be huge, describe your (real) problem now for better help.

    Regards,
    Bengt Richter
     
    Bengt Richter, Apr 8, 2005
    #17
  18. Matthew Thorley wrote:
    > Scott David Daniels wrote: ...(explaining Python has no "the" parent)
    > I see what your saying, but I my situation the values of the dictionary
    > are unique objects created by a parent object.

    But that is your convention, not Python's. Some good general rules:
    1) For frequent (or fast) access you should know where something is,
    rather than search for it.
    2) You (your app) should be willing to "pay" for your own needs for
    navigation rather than expect a built-in cost for everyone that
    provides convenience for a few.
    3) A very "Pythonic" storage system makes it clear how you navigate,
    so relying on magic is usually a bad idea.

    > When the 'root object' is 'global' I see what your saying, but when
    >
    > class A:
    > def __init__(self, container):
    > self.container=container
    >
    > class B(dict):
    > def magice_get_parent(self):
    > ...
    >
    > class special_value():
    > def __init__(self, val):
    > self.val = val
    >
    > def magic_get_key(self):
    > ...
    >
    > parent = A(B)
    > parent.container[x] = special_value(1)
    > parent.container[y] = special_value(2)
    > parent.container[z] = special_value(1)



    OK, if you want help, try doing code, not sketching what it might be.
    > class special_value():

    Cannot be. Perhaps:
    class special_value(object):

    > class A:
    > def __init__(self, container):
    > self.container=container

    ....
    > class B(dict):

    ....
    > parent = A(B)
    > parent.container[x] = ...


    Either you must use:
    parent = A(B())

    or
    class A:
    def __init__(self, containerClass):
    self.container = containerClass()

    By the way, if you are subclassing dict, you might as well
    use new-style throughout (so: class A(object): ...).

    Now, how about rather than all of this magic, trying:

    class A:
    def __init__(self, container):
    self.container = container
    self.container.parent = self

    and instead of

    > parent.container[x] = special_value(1)


    parent.container.set(x, special_value(1))


    using:
    class B(dict):
    ...
    def set(self, key, contents):
    self[key] = contents
    contents.origin = self, key
    ...

    Then after:
    parent = A(B())
    parent.container.set(x, special_value(1))
    parent.container.set(y, special_value(2))
    parent.container.set(z, special_value(1))

    You can do:

    child = parent.container
    print child.parent

    value1 = parent.container[x]
    box, key = value1.origin
    assert box[key] is value1 and box.parent is parent

    And you didn't have to use magic at all.

    --Scott David Daniels
     
    Scott David Daniels, Apr 8, 2005
    #18
  19. On Fri, 08 Apr 2005 10:33:53 -0600, Matthew Thorley wrote:
    > I must say I am *very* suprised that python does not have a way to look
    > up what key is pointing to a given object--without scanning the whole
    > list that is.


    Assuming fairly optimal data structures, nothing is free.

    Python chooses not to have bi-directional dicts built in. A good reason
    for this is that it is easy to build a two-way dict out of two one-way
    dicts, and there's no obvious way to build a "built-in" two-way dict that
    is any more efficient than that.

    Python chooses to allow all objects potentially to be dict keys, which has
    overhead vs. an implementation such as that in Perl that only allows
    strings. Either of those is tolerable ultimately, though I do prefer
    Python's approach as I key things on objects all the time.

    It's all a matter of tradeoffs. Building all the dicts as two-way in
    memory consumes twice the memory and twice the processor power for a lot
    of situations where the second direction isn't used, so *on average*
    that's not a good tradeoff.

    Even though Python doesn't have a built-in way, it is easy to write your
    own class that interoperates transparently, and there are many ones you
    can grab off the 'net, even given to you in this thread :)
     
    Jeremy Bowers, Apr 8, 2005
    #19
  20. Matthew Thorley

    Terry Reedy Guest

    "Matthew Thorley" <> wrote in message
    news:d36bpj$s59$...
    > I must say I am *very* suprised that python does not have a way to look
    > up what key is pointing to a given object


    But it does. Of course, there could be zero to many keys in any dictionary
    pointing to any particular value object

    >--without scanning the whole list that is.


    That's one way. Another is a reverse dict (for hashable values turned into
    keys) with the value being a list of zero to many keys. A third (and
    fastest of these) is to keep the key with the value.

    >Is that what list.index() does under-the-hood? I mean is
    > list.index(y) just the same as
    >
    > itemnum = 0
    > for item in list:
    > if y == item:
    > return itemnum
    > else:
    > itemnum = itemnum+1


    More or less, yes. If your list is sorted, you can use binary search in
    the bisect module.

    Terry J. Reedy
     
    Terry Reedy, Apr 8, 2005
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Noah
    Replies:
    2
    Views:
    278
  2. Girish Sahani
    Replies:
    11
    Views:
    628
    Roberto Bonvallet
    Jun 7, 2006
  3. Replies:
    14
    Views:
    595
    Antoon Pardon
    Jul 4, 2006
  4. Delaney, Timothy (Tim)
    Replies:
    4
    Views:
    332
  5. Arvin Portlock
    Replies:
    3
    Views:
    155
    Brian McCauley
    Feb 13, 2004
Loading...

Share This Page