class A():
def __init__(self, data=''):
self.data = data
def __str__(self):
return str(self.data)
d = {}
elem = A()
d[elem] = 'abc'
elem2 = A()
print d[elem2] # KeyError
# actually elem2! was used not elem
how can I implement this without error?
I tried to get d[elem2] (not elem) with another instance of A() BUT with the same content.
The answer is yes, you need to redefine __hash__() and __eq__():
>>> class A(object):
... def __init__(self, data=''):
... self.data = data
... def __eq__(self, another):
... return hasattr(another, 'data') and self.data == another.data
... def __hash__(self):
... return hash(self.data)
...
>>> a1, a2, a3 = A('foo'), A('foo'), A('bar')
>>> d = {a1: 'foo'}
>>> d[a1]
'foo'
>>> d[a2]
'foo'
>>> d[a3]
Traceback (most recent call last):
File "", line 1, in
KeyError: __main__.A object at 0x927d0>
As explained in another comment default implementation of __hash__ is just simple identity, so if you want to make it more sophisticated, you need to define it explicitly.
What you did should work, as long as you don't override the __hash__() and __eq__() methods. It will use object identity as equality. If you want a different notion of equality, you can override the __hash__() and __eq__() methods of your class.
Related
Let's say I have an Entity class:
class Entity(dict):
pass
def save(self):
...
I can wrap a dict object with Entity(dict_obj)
But is it possible to create a class that can wrap any type of objects, eg. int, list etc.
PS I have come up the following work around, it doesn't work on the more complex objects, but seems to work with basic ones, completely unsure if there are any gotchas, might get penalised with efficiency by creating the class every time, please let me know:
class EntityMixin(object):
def save(self):
...
def get_entity(obj):
class Entity(obj.__class__, EntityMixin):
pass
return Entity(obj)
Usage:
>>> a = get_entity(1)
>>> a + 1
2
>>> b = get_entity('b')
>>> b.upper()
'B'
>>> c = get_entity([1,2])
>>> len(c)
2
>>> d = get_entity({'a':1})
>>> d['a']
1
>>> d = get_entity(map(lambda x : x, [1,2]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jlin/projects/django-rest-framework-queryset/rest_framework_queryset/entity.py", line 11, in get_entity
return Entity(obj)
TypeError: map() must have at least two arguments.
Improve efficiency:
EntityClsCache = {}
class EntityMixin(object):
def save(self):
...
def _get_entity_cls(obj):
class Entity(obj.__class__, EntityMixin):
pass
return Entity
def get_entity(obj)
cls = None
try:
cls = EntityClsCache[obj.__class__]
except AttributeError:
cls = _get_entity_cls(obj)
EntityClsCache[obj.__class__] = cls
return cls(obj)
The solution you propose looks elegant, but it lacks caching, as in, you'll construct a unique class every time get_entity() is called, even if types are all the same.
Python has metaclasses, which act as class factories. Given that metaclass' methods override these of class, not the instance, we can implement class caching:
class EntityMixin(object):
pass
class CachingFactory(type):
__registry__ = {}
# Instead of declaring an inner class,
# we can also return type("Wrapper", (type_, EntityMixin), {}) right away,
# which, however, looks more obscure
def __makeclass(cls, type_):
class Wrapper(type_, EntityMixin):
pass
return Wrapper
# This is the simplest form of caching; for more realistic and less error-prone example,
# better use a more unique/complex key, for example, tuple of `value`'s ancestors --
# you can obtain them via type(value).__mro__
def __call__(cls, value):
t = type(value)
typename = t.__name__
if typename not in cls.__registry__:
cls.__registry__[typename] = cls.__makeclass(t)
return cls.__registry__[typename](value)
class Factory(object):
__metaclass__ = CachingFactory
This way, Factory(1) performs Factory.__call__(1), which is CachingFactory.__call__(1) (without metaclass, that'd be a constructor call instead, which would result in a class instance -- but we want to make a class first and only then instantiate it).
We can ensure that the objects created by Factory are the instances of the same class, which is crafted specifically for them at the first time:
>>> type(Factory(map(lambda x: x, [1, 2]))) is type(Factory([1]))
True
>>> type(Factory("a")) is type(Factory("abc"))
True
Is there a way in Python 3 to recursively call private member variables unique __str__ functions programmatically? Something like:
class A:
def __str__(self):
return "A"
class B:
def __str__(self):
return "B"
class C:
def __init__(self):
self._A = A()
self._B = B()
def __str__(self):
for var in vars(self):
return str(var)
When calling the individual private members, it works fine. Would like a method to do it dynamically however.
Thanks so much.
The vars function returns a dictionary where the keys are the variable names (as strings) and the values are the values of the variable. So iterating over the values should work.
class A:
def __str__(self):
return "A"
class B:
def __str__(self):
return "B"
class C:
def __init__(self):
self._A = A()
self._B = B()
def __str__(self):
output = ""
for _,var in vars(self).items(): #Iterate over the values
output += str(var) #Use the str() function here to make the object return its string form
return output #Need to return instead of print since that is what the __str__() function should do
You can add some kind of separator (like a \n) between the values if you want. Just replace str(var) with str(var) + "\n".
You can also use the dictionary keys; vars() is self.__dict__:
>>> class A:
... def __str__(self):
... return self.__class__.__name__
...
>>> class B:
... def __str__(self):
... return self.__class__.__name__
...
>>> str(A())
'A'
>>> repr(A()) # "long-form" the hex-string is id()
'<__main__.A object at 0x10f65a908>'
>>> class C:
... def __init__(self):
... self.A = A()
... self.B = B()
... def __str__(self):
... return '\n'.join(self.__dict__)
...
>>> C()
<__main__.C object at 0x10f65aa58>
>>> print(C()) # Uses str(C())
A
B
vars(self) is effectively self. In turn, self.__dict__ is a dict used to store an object’s (writable) attributes.
>>> C().__dict__
{'A': <__main__.A object at 0x10f65aa90>, 'B': <__main__.B object at 0x10f65aac8>}
The signature is '\n'.join(iterable), and when you iterate over a dictionary, you iterate over its keys, which suffices in this case.
Note on Dataclasses
I'm not totally sure if (Python 3.7+) dataclasses are an easier solution here. That's because they automatically implement a __repr__() but not a __str__() as far as I can tell:
>>> from dataclasses import dataclass
>>>
>>> #dataclass
... class C:
... _A: object = A()
... _B: object = B()
...
>>> c = C() # still uses repr() for each field
>>> str(c)
'C(_A=<__main__.A object at 0x10f373828>, _B=<__main__.B object at 0x10f373940>)'
In other words, you'd need to replace A.__str__ with A.__repr__ (same for B, which is maybe not something you want to do in the first place with regards to those two classes.)
Are you sure you shouldn't be using __repr__?
Anyway, here's an example using attrs, beacuse I'm stuck on Python 3.5. With dataclasses it will work in a similar manner.
import attr
class A:
def __str__(self):
return 'A'
class B:
def __str__(self):
return 'B'
#attr.s
class C:
a = attr.ib(default=attr.Factory(A))
b = attr.ib(default=attr.Factory(B))
if __name__ == '__main__':
c = C()
print(c) # __str__ defaults to __repr__
def __str__(self):
bits = ['<C']
for a in self.__attrs_attrs__:
bits.append(' %s=%s' % (a.name, getattr(self, a.name)))
bits.append('>')
return ''.join(bits)
C.__str__ = __str__
print(c) # custom __str__
I know the questions about: copy properties, or dynamic creation of properties has already been posted and also been answered (here, here and here). You could also find an excellent description, how the property function works here.
But I think, that my question is a bit more specific. I do not only want to copy the property from one class to another. No, I also want the specific getter, setter and deleter functions to be copied to the destination class. After a whole day of searching for an answer, I decided to create an new post for this question.
So let me get a bit more in detail. A have an attribute class which is more a class group and stores property-classes:
class AttrContainer():
class a():
ATTR=1
#property
def a(self):
return self.ATTR
#a.setter
def a(self, n):
self.ATTR = n + 3.021
class b():
ATTR=None
#property
def b(self):
return "Something"
class c():
ATTR=None
#property
def c(self):
return 3
#c.setter
def c(self, n):
self.ATTR = n - 8.5201
As you can see, I have different getter, setter (not in the example: deleter) definitions of each property.
I want to use those properties with my item "wrapper" objects. But not all of item objects needs all properties, thats why I want to copy them dynamically into my wrapper classes.
So, this is how my item "wrapper" classes looks like:
class Item01Object():
properties = ["a","c"]
ATTR = None
#[...]
class Item02Object():
properties = ["b","c"]
ATTR = None
#[...]
#[...]
Because I can't set the properties dynamically while the item class will be instanced, I have to set them before I instance the class:
def SetProperties( ItemObject ):
for propName, cls in AttrContainer.__dict__.iteritems():
if propName in ItemObject.properties:
prop = cls.__dict__[propName]
fget = prop.fget if prop.fget else None
fset = prop.fset if prop.fset else None
fdel = prop.fdel if prop.fdel else None
ItemObject.__dict__[propName] = property(fget,fset,fdel)
return ItemObject()
In the end, i would instance my ItemObjects like this:
item = SetProperties(Item01Object)
I would expect, that this will work...
>>> print item
<__builtin__.Item01Object instance at 0x0000000003270F88>
>>> print item.a
None
This is result is right, because I do not update my property ATTR..
Lets change the property:
>>> item.a = 20
>>> print item.a
20
But this result is wrong, it should be 23.021 and NOT 20 . It looks like my properties do not using the setter functions from its classes.
Why? What do I wrong in my code?
Edit: Sorry, I forgot to remove the inherited object of the ItemObject classes.. Now the code works.
For properties with setters and deleters to work properly, your classes need to inherit from object: Why does #foo.setter in Python not work for me?
You can just copy the property object itself over to the new class. It'll hold references to the getter, setter and deleter functions and there is no need to copy those across.
For new-style classes, your code is not working; you cannot assign to a class __dict__ attribute:
>>> item = SetProperties(Item01Object)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in SetProperties
TypeError: 'dictproxy' object does not support item assignment
Use setattr() instead to set attributes on new-style classes:
def SetProperties( ItemObject ):
for propName, cls in AttrContainer.__dict__.iteritems():
if propName in ItemObject.properties:
setattr(ItemObject, propName, cls.__dict__[propName])
return ItemObject()
Note that the property object is copied across wholesale.
Demo:
>>> class Item01Object(object):
... properties = ["a","c"]
... ATTR = None
...
>>> def SetProperties( ItemObject ):
... for propName, cls in AttrContainer.__dict__.iteritems():
... if propName in ItemObject.properties:
... setattr(ItemObject, propName, cls.__dict__[propName])
... return ItemObject()
...
>>> item = SetProperties(Item01Object)
>>> item
<__main__.Item01Object object at 0x108205850>
>>> item.a
>>> item.a = 20
>>> item.a
23.021
You only have to copy across property objects to the target class once though; that your function returns an instance implies you are planning to use it for all instances created.
I'd make it a decorator instead:
def set_properties(cls):
for name, propcls in vars(AttrContainer).iteritems():
if name in cls.properties:
setattr(cls, name, vars(propcls)[name])
return cls
then use this on each of your Item*Object classes:
#set_properties
class Item01Object(object):
properties = ["a","c"]
ATTR = None
#set_properties
class Item02Object(object):
properties = ["b","c"]
ATTR = None
Demo:
>>> def set_properties(cls):
... for name, propcls in vars(AttrContainer).iteritems():
... if name in cls.properties:
... setattr(cls, name, vars(propcls)[name])
... return cls
...
>>> #set_properties
... class Item01Object(object):
... properties = ["a","c"]
... ATTR = None
...
>>> #set_properties
... class Item02Object(object):
... properties = ["b","c"]
... ATTR = None
...
>>> item01 = Item01Object()
>>> item01.c = 20
>>> item01.c
3
>>> item02 = Item02Object()
>>> item02.b = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> item02.b
'Something'
Let's say I have a class like this:
class Test(object):
prop = property(lambda self: "property")
The descriptor takes priority whenever I try to access Test().prop. So that will return 'property'. If I want to access the object's instance storage, I can do:
x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])
However if I change my class to:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
How do I do the same, and access the internal storage of x, to write 12 and read it back, since x.__dict__ no longer exist?
I am fairly new with Python, but I understand the Python philosophy is to give complete control, so why is an implementation detail preventing me from doing that?
Isn't Python missing a built-in function that could read from an instance internal storage, something like:
instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])
which would work like vars, except it also works with __slots__, and with built-in types that don't have a __dict__?
Short answer, You can't
The problem is that slots are themselves implemented in terms of descriptors. Given:
class Test(object):
__slots__ = ("prop",)
t = Test()
the phrase:
t.prop
Is translated, approximately to:
Test.prop.__get__(t, Test)
where Test.prop is a <type 'member_descriptor'> crafted by the run-time specifically to load prop values out of Test instances from their reserved space.
If you add another descriptor to the class body definition, it masks out the member_descriptor that would let you get to the slotted attribute; there's no way to ask for it, it's just not there anymore. It's effectively like saying:
class Test(object):
#property
def prop(self):
return self.__dict__['prop']
#property
def prop(self):
return "property"
You've defined it twice. there's no way to "get at" the first prop definition.
but:
Long answer, you can't in a general way. You can
You can still abuse the python type system to get at it using another class definition. You can change the type of a python object, so long as it has the exact same class layout, which roughly means that it has all of the same slots:
>>> class Test1(object):
... __slots__ = ["prop"]
... prop = property(lambda self: "property")
...
>>> class Test2(object):
... __slots__ = ["prop"]
...
>>> t = Test1()
>>> t.prop
'property'
>>> t.__class__ = Test2
>>> t.prop = 5
>>> t.prop
5
>>> t.__class__ = Test1
>>> t.prop
'property'
But there's no general way to introspect an instance to work out its class layout; you just have to know from context. You could look at it's __slots__ class attribute, but that won't tell you about the slots provided in the superclass (if any) nor will it give you any hint if that attribute has changed for some reason after the class was defined.
I don't quite understand what and why you want to do this, but does this help you?
>>> class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
>>> a = Test()
>>> b = Test()
>>> a.prop
'property'
>>> tmp = Test.prop
>>> Test.prop = 23
>>> a.prop
23
>>> Test.prop = tmp; del tmp
>>> b.prop
'property'
of course, you cannot overwrite the property on a per-instance basis, that's the whole point of slotted descriptors.
Note that subclasses of a class with __slots__ do have a __dict__ unless you manually define __slots__, so you can do:
>>> class Test2(Test):pass
>>> t = Test2()
>>> t.prop
'property'
>>> t.__dict__['prop'] = 5
>>> t.__dict__['prop']
5
>>> Test2.prop
<property object at 0x00000000032C4278>
but still:
>>> t.prop
'property'
and that's not because of __slots__, it's the way descriptors work.
your __dict__ is bypassed on attribute lookup, you are just abusing it as data structure that happens to be there for storing a state.
it is equivalent to do this:
>>> class Test(object):
__slots__ = ("prop", "state")
prop = property(lambda self: "property")
state = {"prop": prop}
>>> t.prop
'property'
>>> t.state["prop"] = 5
>>> t.state["prop"]
5
>>> t.prop
'property'
If you really ever want to do something like that, and you REALL REALLY need something like that, you can always override __getattribute__ and __setattribute__, it's just as stupid... This is just to prove it to you:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
__internal__ = {}
def __getattribute__(self, k):
if k == "__dict__":
return self.__internal__
else:
try:
return object.__getattribute__(self, k)
except AttributeError, e:
try:
return self.__internal__[k]
except KeyError:
raise e
def __setattribute__(self, k, v):
self.__internal__[k] = v
object.__setattribute__(self, k, v)
t = Test()
print t.prop
t.__dict__["prop"] = "test"
print "from dict", t.__dict__["prop"]
print "from getattr", t.prop
import traceback
# These won't work: raise AttributeError
try:
t.prop2 = "something"
except AttributeError:
print "see? I told you!"
traceback.print_exc()
try:
print t.prop2
except AttributeError:
print "Haha! Again!"
traceback.print_exc()
(Tried it on Python 2.7)
It's exactly what you expect I guess. Don't do this, it's useless.
Is there any way to make a list of classes behave like a set in python?
Basically, I'm working on a piece of software that does some involved string comparison, and I have a custom class for handling the strings. Therefore, there is an instance of the class for each string.
As a result, I have a large list containing all these classes. I would like to be able to access them like list[key], where in this case, the key is a string the class is based off of (note: the string will never change once the class is instantiated, so it should be hashable).
It seems to me that I should be able to do this somewhat easily, by adding something like __cmp__ to the class, but either I'm being obtuse (likely), or I'm missing something in the docs.
Basically, I want to be able to do something like this (Python prompt example):
>>class a:
... def __init__(self, x):
... self.var = x
...
>>> from test import a
>>> cl = set([a("Hello"), a("World"), a("Pie")])
>>> print cl
set([<test.a instance at 0x00C866C0>, <test.a instance at 0x00C866E8>, <test.a instance at 0x00C86710>])
>>> cl["World"]
<test.a instance at 0x00C866E8>
Thanks!
Edit Some additional Tweaks:
class a:
... def __init__(self, x):
... self.var = x
... def __hash__(self):
... return hash(self.var)
...
>>> v = a("Hello")
>>> x = {}
>>> x[v]=v
>>> x["Hello"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Hello'
>>> x["Hello"]
Just write a class that behaves a bit like a mapping:
class ClassDict(object):
def __init__(self):
self.classes = {}
def add(self, cls):
self.classes[cls.__name__] = cls
def remove(self, cls):
if self.classes[cls.__name__] == cls:
del self.classes[cls.__name__]
else:
raise KeyError('%r' % cls)
def __getitem__(self, key):
return self.classes[key]
def __repr__(self):
return 'ClassDict(%s)' % (', '.join(self.classes),)
class C(object):
pass
class D(object):
pass
cd = ClassDict()
cd.add(C)
cd.add(D)
print cd
print cd['C']
Why don't you just do:
>>> v = MyStr("Hello")
>>> x = {}
>>> x[v.val]=v
>>> x["Hello"]
MyStr("Hello")
Why go through all the trouble of trying to create a hand-rolled dict that uses different keys than the ones you pass in? (i.e. "Hello" instead of MyStr("Hello")).
ex.
class MyStr(object):
def __init__(self, val):
self.val = str(val)
def __hash__(self):
return hash(self.val)
def __str__(self):
return self.val
def __repr__(self):
return 'MyStr("%s")' % self.val
>>> v = MyStr("Hello")
>>> x = {}
>>> x[str(v)]=v
>>> x["Hello"]
MyStr("Hello")
Set and dict use the value returned by an object's __hash__ method to look up the object, so this will do what you want:
>>class a:
... def __init__(self, x):
... self.var = x
...
... def __hash__(self):
... return hash(self.var)
As I remember "set" and "dict" uses also __hash__
From Python 2.x doc:
A dictionary’s keys are almost arbitrary values. Values that are not hashable, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may not be used as keys.
Do you want something like this
class A(object):
ALL_INSTANCES = {}
def __init__(self, text):
self.text = text
self.ALL_INSTANCES[self.text] = self
a1 = A("hello")
a2 = A("world")
print A.ALL_INSTANCES["hello"]
output:
<__main__.A object at 0x00B7EA50>