dict: retrieve the original key by key
Dear python experts, I use a huge python dictionary where the values are lists of that dictionary's keys (yes, a graph). Each key is thus referenced several times. As the keys are rather large objects, I would like to save memory by re-using key objects wherever possible, instead of having several equal objects in memory. There does not seem to be a way to retrieve the original key from a python dictionary. Is there a technical reason for this? (Other than that such functionality was not considered to be useful enough.) What I will probably do now is store (key, real_value) as values in my dictionary. Is there a better solution? thanks, Christoph -- http://mail.python.org/mailman/listinfo/python-list
Re: dict: retrieve the original key by key
Chris Rebert writes: > On Sun, May 15, 2011 at 1:28 AM, Christoph Groth wrote: >> I use a huge python dictionary where the values are lists of that >> dictionary's keys (yes, a graph). Each key is thus referenced >> several times. >> >> As the keys are rather large objects, I would like to save memory by >> re-using key objects wherever possible, instead of having several >> equal objects in memory. >> >> There does not seem to be a way to retrieve the original key from a >> python dictionary. Is there a technical reason for this? (Other >> than that such functionality was not considered to be useful enough.) > > Define "original key". def original_key(dictionary, key): for k in dictionary: if k == key: return k raise KeyError(key) But this is not efficient. I would like to avoid having _multiple_ objects which are equal (a == b) but not the same (a is not b). This would save a lot of memory. -- http://mail.python.org/mailman/listinfo/python-list
Re: dict: retrieve the original key by key
Steven D'Aprano writes: > On Sun, 15 May 2011 11:11:41 +0200, Christoph Groth wrote: > >> I would like to avoid having _multiple_ objects which are equal (a == >> b) but not the same (a is not b). This would save a lot of memory. > > Based on the idea of interning, which is used for Python strings: > > cache = {} def my_intern(obj): > return cache.setdefault(obj, obj) > > > x = make_some_object() x = my_intern(x) > > This ensures that equal objects in the graph are not just equal, but > the same cached object. This requires another dictionary, though. But hey, they keys of my dictionary are actually strings, so I can use the built-in intern. Somehow, I have never stumbled accross this built-in function so far. Thanks a lot for the hint! Christoph -- http://mail.python.org/mailman/listinfo/python-list
constructing an object from another instance of the same class
Dear all, sometimes it is handy to have a function which can take as argument anything which can be converted into something, e.g. def foo(arg): arg = float(arg) # ... I would like to mimic this behavior of float for a user-defined type, e.g. def bar(arg): arg = My_type(arg) # ... Now I wonder what is the most pythonic way to write the __init__ method of My_type? The following comes to my mind: class My_type: def __init__(self, other): if isinstance(other, type(self)): self.a = other.a self.b = other.b return # initialize self in some other way It seems to me that in this way I might get problems when I pass an instance of Derived_from_my_type to bar, as it will become an instance of My_type. What is a good way to express this? In C++ (which I know better than python) I would make bar accept a const reference to My_type. Then I could use it directly with instances of My_type, Derived_from_my_type and other types which can be converted into My_type. thanks Christoph -- http://mail.python.org/mailman/listinfo/python-list
Re: constructing an object from another instance of the same class
Bruno Desthuilliers writes: >> It seems to me that in this way I might get problems when I pass an >> instance of Derived_from_my_type to bar, as it will become an >> instance of My_type. > > The instance you pass to bar won't "become" anything else. You create > a new My_type instance from the Derived_from_my_type one's values, and > rebinding the _local_ name 'arg' only affects the local namespace. I understand that it won't become an instance of My_type globally. But it will become locally and this breaks polymorphism. (See code example I provide at the end) >> In C++ > > Forget about C++ - Python is a different beast !-) Still, it is useful and interesting to compare languages. Like in the real world it is also insightful to compare the grammar of quite different languages. >> (which I know better than python) I would make bar accept a const >> reference to My_type. Then I could use it directly with instances of >> My_type, Derived_from_my_type and other types which can be converted >> into My_type. > > If you only worry about being able to use any "My_type like" object - > that is, any object implementing a given subset of My_type's > interface, then just document your expectations in the function's > docstring and use whatever object is passed in as if it was a My_type > instance. Period. As long as you document what your function expects, > it's the caller's responsaibility to make sure it provides something > compatible. If he don't, well he'll get a nice traceback. This is not what I am worrying about. I will try to be more explicit. I would like to have a class for a "special matrix". This is an ordinary 2n by 2n matrix which can be thought of as consisting of four n by n sized blocks. At this moment, I just use normal numpy arrays (or anything which behaves like them). But I have very good reasons to actually have a class for these special matrices. Still, I would like to be able to call functions which work with "special matrices" with plain numpy arrays as arguments. In that case, the arguments which are plain matrices should be converted to "special" ones such that the main part of the function can assume to always work with "special matrices". The code attached in the end (which is a complete runnable script) should illustrate what I mean. This example works as I want except that when bar is called with a an argument of type Derived, it behaves as Base. Also, I am not sure whether there is a nicer way to achieve the following functionality for Base.__init__: If other is of type Base already, just "pass it on". Otherwise, construct an instance of Base from it. import numpy as np class Base: def __init__(self, other): if isinstance(other, type(self)): self = other return n = other.shape[0] assert n == other.shape[1] assert n % 2 == 0 n //= 2 self.a = other[0 : n, 0 : n] self.b = other[n : 2*n, 0 : n] self.c = other[0 : n, n : 2*n] self.d = other[n : 2*n, n : 2*n] def hello(self): print 'hello from Base' class Derived(Base): def hello(self): print 'hello from Derived' def bar(arg): arg = Base(arg) # Do something useful with arg.{a..d} arg.hello() # This works. a = np.identity(4) bar(a) # And this also. a = Base(np.identity(4)) bar(a) # But this prints "hello from Base"! a = Derived(np.identity(4)) bar(a) -- http://mail.python.org/mailman/listinfo/python-list
Re: constructing an object from another instance of the same class
Bruno Desthuilliers writes: > Anyway: the simplest solution here is to replace the call to your Base > class with a call to a factory function. I'd probably go for something > like (Q&D untested code and other usual warnings) : > > (...) Yeah, that will do what I want. My confusion arose from the expectation that there had to be some mechanism to do the conversion automatically. But actually a simple def bar(arg): if not isinstance(arg, Base): arg = Base(arg) # Do something with arg. is a simple and explicit solution of the problem. Thanks Christoph -- http://mail.python.org/mailman/listinfo/python-list
Re: constructing an object from another instance of the same class
Steven D'Aprano writes: > On Fri, 18 Jun 2010 16:30:00 +0200, Christoph Groth wrote: > >> If other is of type Base already, just "pass it on". Otherwise, >> construct an instance of Base from it. >> >> import >> numpy as np >> >> class Base: >> def __init__(self, other): >> if isinstance(other, type(self)): >> self = other >> return > > This does not do what you think it does. I wonder whether you've > actually tried it? Just quickly. Sorry, I should have written class Base: def __init__(self, other): if isinstance(other, type(self)): self.a = other.a self.b = other.b self.c = other.c self.d = other.d return # ... -- http://mail.python.org/mailman/listinfo/python-list