Let's say I've got a simple class in python
class Wharrgarbl(object):
def __init__(self, a, b, c, sum, version='old'):
self.a = a
self.b = b
self.c = c
self.sum = 6
self.version = version
def __int__(self):
return self.sum + 9000
def __what_goes_here__(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
I can cast it to an integer very easily
>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> int(w)
9006
Which is great! But, now I want to cast it to a dict in a similar fashion
>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}
What do I need to define for this to work? I tried substituting both __dict__ and dict for __what_goes_here__, but dict(w) resulted in a TypeError: Wharrgarbl object is not iterable in both cases. I don't think simply making the class iterable will solve the problem. I also attempted many googles with as many different wordings of "python cast object to dict" as I could think of but couldn't find anything relevant :{
Also! Notice how calling w.__dict__ won't do what I want because it's going to contain w.version and w.sum. I want to customize the cast to dict in the same way that I can customize the cast to int by using def int(self).
I know that I could just do something like this
>>> w.__what_goes_here__()
{'a': 'one', 'c': 'three', 'b': 'two'}
But I am assuming there is a pythonic way to make dict(w) work since it is the same type of thing as int(w) or str(w). If there isn't a more pythonic way, that's fine too, just figured I'd ask. Oh! I guess since it matters, this is for python 2.7, but super bonus points for a 2.4 old and busted solution as well.
There is another question Overloading __dict__() on python class that is similar to this one but may be different enough to warrant this not being a duplicate. I believe that OP is asking how to cast all the data in his class objects as dictionaries. I'm looking for a more customized approach in that I don't want everything in __dict__ included in the dictionary returned by dict(). Something like public vs private variables may suffice to explain what I'm looking for. The objects will be storing some values used in calculations and such that I don't need/want to show up in the resulting dictionaries.
UPDATE:
I've chosen to go with the asdict route suggested but it was a tough choice selecting what I wanted to be the answer to the question. Both #RickTeachey and #jpmc26 provided the answer I'm going to roll with but the former had more info and options and landed on the same result as well and was upvoted more so I went with it. Upvotes all around though and thanks for the help. I've lurked long and hard on stackoverflow and I'm trying to get my toes in the water more.
There are at least five six ways. The preferred way depends on what your use case is.
Option 1:
Simply add an asdict() method.
Based on the problem description I would very much consider the asdict way of doing things suggested by other answers. This is because it does not appear that your object is really much of a collection:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
Using the other options below could be confusing for others unless it is very obvious exactly which object members would and would not be iterated or specified as key-value pairs.
Option 1a:
Inherit your class from 'typing.NamedTuple' (or the mostly equivalent 'collections.namedtuple'), and use the _asdict method provided for you.
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
Using a named tuple is a very convenient way to add lots of functionality to your class with a minimum of effort, including an _asdict method. However, a limitation is that, as shown above, the NT will include all the members in its _asdict.
If there are members you don't want to include in your dictionary, you'll need to specify which members you want the named tuple _asdict result to include. To do this, you could either inherit from a base namedtuple class using the older collections.namedtuple API:
from collections import namedtuple as nt
class Wharrgarbl(nt("Basegarble", "a b c")):
# note that the typing info below isn't needed for the old API
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
...or you could create a base class using the newer API, and inherit from that, using only the dictionary members in the base class:
from typing import NamedTuple
class Basegarbl(NamedTuple):
a: str
b: str
c: str
class Wharrgarbl(Basegarbl):
sum: int = 6
version: str = 'old'
Another limitation is that NT is read-only. This may or may not be desirable.
Option 2:
Implement __iter__.
Like this, for example:
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
Now you can just do:
dict(my_object)
This works because the dict() constructor accepts an iterable of (key, value) pairs to construct a dictionary. Before doing this, ask yourself the question whether iterating the object as a series of key,value pairs in this manner- while convenient for creating a dict- might actually be surprising behavior in other contexts. E.g., ask yourself the question "what should the behavior of list(my_object) be...?"
Additionally, note that accessing values directly using the get item obj["a"] syntax will not work, and keyword argument unpacking won't work. For those, you'd need to implement the mapping protocol.
Option 3:
Implement the mapping protocol. This allows access-by-key behavior, casting to a dict without using __iter__, and also provides two types of unpacking behavior:
mapping unpacking behavior: {**my_obj}
keyword unpacking behavior, but only if all the keys are strings: dict(**my_obj)
The mapping protocol requires that you provide (at minimum) two methods together: keys() and __getitem__.
class MyKwargUnpackable:
def keys(self):
return list("abc")
def __getitem__(self, key):
return dict(zip("abc", "one two three".split()))[key]
Now you can do things like:
>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m) # cast to dict directly
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m) # unpack as kwargs
{'a': 'one', 'b': 'two', 'c': 'three'}
As mentioned above, if you are using a new enough version of python you can also unpack your mapping-protocol object into a dictionary comprehension like so (and in this case it is not required that your keys be strings):
>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}
Note that the mapping protocol takes precedence over the __iter__ method when casting an object to a dict directly (without using kwarg unpacking, i.e. dict(m)). So it is possible- and might be sometimes convenient- to cause the object to have different behavior when used as an iterable (e.g., list(m)) vs. when cast to a dict (dict(m)).
But note also that with regular dictionaries, if you cast to a list, it will give the KEYS back, and not the VALUES as you require. If you implement another nonstandard behavior for __iter__ (returning values instead of keys), it could be surprising for other people using your code unless it is very obvious why this would happen.
EMPHASIZED: Just because you CAN use the mapping protocol, does NOT mean that you SHOULD do so. Does it actually make sense for your object to be passed around as a set of key-value pairs, or as keyword arguments and values? Does accessing it by key- just like a dictionary- really make sense? Would you also expect your object to have other standard mapping methods such as items, values, get? Do you want to support the in keyword and equality checks (==)?
If the answer to these questions is yes, it's probably a good idea to not stop here, and consider the next option instead.
Option 4:
Look into using the 'collections.abc' module.
Inheriting your class from 'collections.abc.Mapping or 'collections.abc.MutableMapping signals to other users that, for all intents and purposes, your class is a mapping * and can be expected to behave that way. It also provides the methods items, values, get and supports the in keyword and equality checks (==) "for free".
You can still cast your object to a dict just as you require, but there would probably be little reason to do so. Because of duck typing, bothering to cast your mapping object to a dict would just be an additional unnecessary step the majority of the time.
This answer from me about how to use ABCs might also be helpful.
As noted in the comments below: it's worth mentioning that doing this the abc way essentially turns your object class into a dict-like class (assuming you use MutableMapping and not the read-only Mapping base class). Everything you would be able to do with dict, you could do with your own class object. This may be, or may not be, desirable.
Also consider looking at the numerical abcs in the numbers module:
https://docs.python.org/3/library/numbers.html
Since you're also casting your object to an int, it might make more sense to essentially turn your class into a full fledged int so that casting isn't necessary.
Option 5:
Look into using the dataclasses module (Python 3.7+ only), which includes a convenient asdict() utility method.
from dataclasses import dataclass, asdict, field, InitVar
#dataclass
class Wharrgarbl(object):
a: int
b: int
c: int
sum: InitVar[int] # note: InitVar will exclude this from the dict
version: InitVar[str] = "old"
def __post_init__(self, sum, version):
self.sum = 6 # this looks like an OP mistake?
self.version = str(version)
Now you can do this:
>>> asdict(Wharrgarbl(1,2,3,4,"X"))
{'a': 1, 'b': 2, 'c': 3}
Option 6:
Use typing.TypedDict, which has been added in python 3.8.
NOTE: option 6 is likely NOT what the OP, or other readers based on the title of this question, are looking for. See additional comments below.
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
Using this option, the resulting object is a dict (emphasis: it is not a Wharrgarbl). There is no reason at all to "cast" it to a dict (unless you are making a copy).
And since the object is a dict, the initialization signature is identical to that of dict and as such it only accepts keyword arguments or another dictionary.
>>> w = Wharrgarbl(a=1,b=2,b=3)
>>> w
{'a': 1, 'b': 2, 'c': 3}
>>> type(w)
<class 'dict'>
Emphasized: the above "class" Wharrgarbl isn't actually a new class at all. It is simply syntactic sugar for creating typed dict objects with specific keys ONLY and value fields of different types for the type checker. At run time, it is still nothing more than a dict.
As such this option can be pretty convenient for signaling to readers of your code (and also to a type checker such as mypy) that such a dict object is expected to have specific keys with specific value types.
But this means you cannot, for example, add other methods, although you can try:
class MyDict(TypedDict):
def my_fancy_method(self):
return "world changing result"
...but it won't work:
>>> MyDict().my_fancy_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'
* "Mapping" has become the standard "name" of the dict-like duck type
There is no magic method that will do what you want. The answer is simply name it appropriately. asdict is a reasonable choice for a plain conversion to dict, inspired primarily by namedtuple. However, your method will obviously contain special logic that might not be immediately obvious from that name; you are returning only a subset of the class' state. If you can come up with with a slightly more verbose name that communicates the concepts clearly, all the better.
Other answers suggest using __iter__, but unless your object is truly iterable (represents a series of elements), this really makes little sense and constitutes an awkward abuse of the method. The fact that you want to filter out some of the class' state makes this approach even more dubious.
something like this would probably work
class MyClass:
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
def __iter__(self): #overridding this to return tuples of (key,value)
return iter([('x',self.x),('y',self.y),('z',self.z)])
dict(MyClass(5,6,7)) # because dict knows how to deal with tuples of (key,value)
I think this will work for you.
class A(object):
def __init__(self, a, b, c, sum, version='old'):
self.a = a
self.b = b
self.c = c
self.sum = 6
self.version = version
def __int__(self):
return self.sum + 9000
def __iter__(self):
return self.__dict__.iteritems()
a = A(1,2,3,4,5)
print dict(a)
Output
{'a': 1, 'c': 3, 'b': 2, 'sum': 6, 'version': 5}
Like many others, I would suggest implementing a to_dict() function rather than (or in addition to) allowing casting to a dictionary. I think it makes it more obvious that the class supports that kind of functionality. You could easily implement such a method like this:
def to_dict(self):
class_vars = vars(MyClass) # get any "default" attrs defined at the class level
inst_vars = vars(self) # get any attrs defined on the instance (self)
all_vars = dict(class_vars)
all_vars.update(inst_vars)
# filter out private attributes
public_vars = {k: v for k, v in all_vars.items() if not k.startswith('_')}
return public_vars
It's hard to say without knowing the whole context of the problem, but I would not override __iter__.
I would implement __what_goes_here__ on the class.
as_dict(self:
d = {...whatever you need...}
return d
I am trying to write a class that is "both" a list or a dict. I want the programmer to be able to both "cast" this object to a list (dropping the keys) or dict (with the keys).
Looking at the way Python currently does the dict() cast: It calls Mapping.update() with the object that is passed. This is the code from the Python repo:
def update(self, other=(), /, **kwds):
''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.
If E present and has a .keys() method, does: for k in E: D[k] = E[k]
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
'''
if isinstance(other, Mapping):
for key in other:
self[key] = other[key]
elif hasattr(other, "keys"):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwds.items():
self[key] = value
The last subcase of the if statement, where it is iterating over other is the one most people have in mind. However, as you can see, it is also possible to have a keys() property. That, combined with a __getitem__() should make it easy to have a subclass be properly casted to a dictionary:
class Wharrgarbl(object):
def __init__(self, a, b, c, sum, version='old'):
self.a = a
self.b = b
self.c = c
self.sum = 6
self.version = version
def __int__(self):
return self.sum + 9000
def __keys__(self):
return ["a", "b", "c"]
def __getitem__(self, key):
# have obj["a"] -> obj.a
return self.__getattribute__(key)
Then this will work:
>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}
Here is very clean and fast solution
I created a function that converts any custom class to dict
def convert_to_dict(args: dict):
json = dict()
for key, value in args.items():
key_vals = str(key).split("_")
last_index = len(key_vals)
json[str(key_vals[last_index-1])] = value
return json
what you need is to supply it object.__dict__ then it will do the job for you to clean it and help you store it in databse.
Going off of the asdict solution, here's a useful mixin for if you want to add asdict to several different classes.
Adapted from: https://www.pythontutorial.net/python-oop/python-mixin/
class DictMixin:
def asdict(self):
return self._traverse_dict(self._attrs)
def _traverse_dict(self, attributes: dict) -> dict:
result = {}
for key, value in attributes.items():
result[key] = self._traverse(value)
return result
def _traverse(self, value):
if isinstance(value, DictMixin):
return value.asdict()
elif isinstance(value, dict):
return self._traverse_dict(value)
elif isinstance(value, list):
return [self._traverse(v) for v in value]
else:
return value
Which you can then use:
class FooBar(DictMixin):
_attrs = ["foo", "hello"]
def __init__(self):
self.foo = "bar"
self.hello = "world"
>>> a = FooBar()
>>> a.asdict()
{
"foo": "bar",
"hello": "world"
}
You can create a folder like 'Strategy' then you can use pickle to save and load the objects of your class.
import pickle
import os
# Load object as dictionary ---------------------------------------------------
def load_object():
file_path = 'Strategy\\All_Pickles.hd5'
if not os.path.isfile(file_path):
return {}
with open(file_path, 'rb') as file:
unpickler = pickle.Unpickler(file)
return dict(unpickler.load())
# Save object as dictionary ---------------------------------------------------
def save_object(name, value):
file_path = 'Strategy\\All_Pickles.hd5'
object_dict = load_object()
with open(file_path, 'wb') as file:
object_dict[name] = value
pickle.dump(object_dict, file)
return True
class MyClass:
def __init__(self, name):
self.name = name
def show(self):
print(self.name)
save_object('1', MyClass('Test1'))
save_object('2', MyClass('Test2'))
objects = load_object()
obj1 = objects['1']
obj2 = objects['2']
obj1.show()
obj2.show()
I created two objects of one class and called a method of the class. I hope, it can help you.
Related
I have a class object that receives some data. Based on a condition, I need that data to change, but only under that condition. Problem I'm running into is that when I call dict.update() , it updates the original variable too. So a subsequent request comes in, and now that original variable is "tainted" so to speak, and is using overridden information that it shouldn't have.
Assuming a dictionary like this:
my_attributes = {"test": True}
And some logic like this:
class MyClass(object):
def __init__(self, attributes):
if my_condition():
attributes.update({"test": False})
The end result:
>>> my_attributes
{'test': False}
So, the next time MyClass is used, those root attributes are still overridden.
I've seemingly gotten around this problem by re-defining attributes:
class MyClass(object):
def __init__(self, attributes):
if my_condition():
attributes = {}
attributes.update(my_attributes)
attributes.update({"test": False})
This has seemed to get around the problem, but I'm not entirely sure this is a good, or even the right, solution to the issue.
Something like this:
class MyClass(object):
#staticmethod
def my_condition():
return True
def __init__(self, attributes):
self.attributes = {**attributes}
if MyClass.my_condition():
self.attributes["test"] = False
my_attributes = {"test": True}
cls_obj = MyClass(my_attributes)
print("my_attributes:", my_attributes, "class.attributes:", cls_obj.attributes)
Output:
my_attributes: {'test': True} class.attributes: {'test': False}
You pass a (mutable) dictionary reference to an object. Now, you have two owners of the reference: the caller of the constructor (the "external world" for the object) and the object itself. These two owners may modify the dictionary. Here is an illustration:
>>> d = {}
>>> def ctor(d): return [d] # just build a list with one element
>>> L = ctor(d)
>>> d[1] = 2
>>> L
[{1: 2}]
>>> L[0][3] = 4
>>> d
{1: 2, 3: 4}
How do you prevent this? Both owners want to protect themselves from wild mutation of their variables. If I were the external world, I would like to pass an immutable reference to the dict, but Python does not provide immutable references for dicts. A copy is the way to go:
>>> d = {}
>>> L = ctor(dict(d)) # I don't give you *my* d
>>> d[1] = 2
>>> L
[{}]
If I were the object, I would do a copy of the object before using it:
>>> d = {}
>>> def ctor2(d): return [dict(d)] # to be sure L[0] is *mine*!
>>> L = ctor2(dict(d)) # I don't give you *my* d
But now you have made two copies of the object just because everyone is scared to see its variables modified by the other. And the issue is still here if the dictionary contains (mutable) references.
The solution is to spell out the responsibilities of each one:
class MyClass(object):
"""Usage: MyClass(attributes).do_something() where attributes is a mapping.
The mapping won't be modified"""
...
Note that this is the common expected behavior: unless specified, the arguments of a function/contructor are not modified. We avoid side effect when possible, but that's not always the case: see list.sort() vs sorted(...).
Hence I think your solution is good. But I prefer to avoid too much logic in the constructor:
class MyClass(object):
#staticmethod
def create_prod(attributes):
attributes = dict(attributes)
attributes.update({"test": False})
return MyClass(attributes)
#staticmethod
def create_test(attributes):
return MyClass(attributes)
def __init__(self, attributes):
self._attributes = attributes # MyClass won't modify attributes
I want to apply a function f to a collection xs but keep its type. If I use map, I get a 'map object':
def apply1(xs, f):
return map(f, xs)
If I know that xs is something like a list or tuple I can force it to have the same type:
def apply2(xs, f):
return type(xs)(map(f, xs))
However, that quickly breaks down for namedtuple (which I am currently in a habbit of using) -- because to my knowledge namedtuple needs to be constructed with unpack syntax or by calling its _make function. Also, namedtuple is const, so I cannot iterate over all entries and just change them.
Further problems arise from use of a dict.
Is there a generic way to express such an apply function that works for everything that is iterable?
Looks like a perfect task for functools.singledispatch decorator:
from functools import singledispatch
#singledispatch
def apply(xs, f):
return map(f, xs)
#apply.register(list)
def apply_to_list(xs, f):
return type(xs)(map(f, xs))
#apply.register(tuple)
def apply_to_tuple(xs, f):
try:
# handle `namedtuple` case
constructor = xs._make
except AttributeError:
constructor = type(xs)
return constructor(map(f, xs))
after that apply function can be simply used like
>>> apply([1, 2], lambda x: x + 1)
[2, 3]
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(10, 5)
>>> apply(p, lambda x: x ** 2)
Point(x=100, y=25)
I'm not aware of what is desired behavior for dict objects though, but the greatness of this approach that it is easy to extend.
I have a hunch you're coming from Haskell -- is that right? (I'm guessing because you use f and xs as variable names.) The answer to your question in Haskell would be "yes, it's called fmap, but it only works with types that have a defined Functor instance."
Python, on the other hand, has no general concept of "Functor." So strictly speaking, the answer is no. To get something like this, you'd have to fall back on other abstractions that Python does provide.
ABCs to the rescue
One pretty general approach would be to use abstract base classes. These provide a structured way to specify and check for particular interfaces. A Pythonic version of the Functor typeclass would be an abstract base class that defines a special fmap method, allowing individual classes to specify how they are to be mapped. But no such thing exists. (I think it would be a really cool addition to Python though!)
Now, you can define your own abstract base classes, so you could create a Functor ABC that expects a fmap interface, but you'd still have to write all your own functorized subclasses of list, dict, and so on, so that's not really ideal.
A better approach would be to use the existing interfaces to cobble together a generic definition of mapping that seems reasonable. You'd have to think pretty carefully about what aspects of the existing interfaces you'd need to combine. Just checking to see whether a type defines __iter__ isn't enough, because as you've already seen, a definition of iteration for a type doesn't necessarily translate into a definition of construction. For example, iterating over a dictionary only gives you the keys, but to map a dictionary in this precise way would require iteration over items.
Concrete examples
Here's an abstract base method that includes special cases for namedtuple and three abstract base classes -- Sequence, Mapping, and Set. It will behave as expected for any type that defines any of the above interfaces in the expected way. It then falls back to the generic behavior for iterables. In the latter case, the output won't have the same type as the input, but at least it will work.
from abc import ABC
from collections.abc import Sequence, Mapping, Set, Iterator
class Mappable(ABC):
def map(self, f):
if hasattr(self, '_make'):
return type(self)._make(f(x) for x in self)
elif isinstance(self, Sequence) or isinstance(self, Set):
return type(self)(f(x) for x in self)
elif isinstance(self, Mapping):
return type(self)((k, f(v)) for k, v in self.items())
else:
return map(f, self)
I've defined this as an ABC because that way you can create new classes that inherit from it. But you can also just call it on an existing instance of any class and it will behave as expected. You could also just use the map method above as a stand-alone function.
>>> from collections import namedtuple
>>>
>>> def double(x):
... return x * 2
...
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(5, 10)
>>> Mappable.map(p, double)
Point(x=10, y=20)
>>> d = {'a': 5, 'b': 10}
>>> Mappable.map(d, double)
{'a': 10, 'b': 20}
The cool thing about defining an ABC is that you can use it as a "mix-in." Here's a MappablePoint derived from a Point namedtuple:
>>> class MappablePoint(Point, Mappable):
... pass
...
>>> p = MappablePoint(5, 10)
>>> p.map(double)
MappablePoint(x=10, y=20)
You could also modify this approach slightly in light of Azat Ibrakov's answer, using the functools.singledispatch decorator. (It was new to me -- he should get all credit for this part of the answer, but I thought I'd write it up for the sake of completeness.)
This would look something like the below. Notice that we still have to special-case namedtuples because they break the tuple constructor interface. That hadn't bothered me before, but now it feels like a really annoying design flaw. Also, I set things up so that the final fmap function uses the expected argument order. (I wanted to use mmap instead of fmap because "Mappable" is a more Pythonic name than "Functor" IMO. But mmap is already a built-in library! Darn.)
import functools
#functools.singledispatch
def _fmap(obj, f):
raise TypeError('obj is not mappable')
#_fmap.register(Sequence)
def _fmap_sequence(obj, f):
if isinstance(obj, str):
return ''.join(map(f, obj))
if hasattr(obj, '_make'):
return type(obj)._make(map(f, obj))
else:
return type(obj)(map(f, obj))
#_fmap.register(Set)
def _fmap_set(obj, f):
return type(obj)(map(f, obj))
#_fmap.register(Mapping)
def _fmap_mapping(obj, f):
return type(obj)((k, f(v)) for k, v in obj.items())
def fmap(f, obj):
return _fmap(obj, f)
A few tests:
>>> fmap(double, [1, 2, 3])
[2, 4, 6]
>>> fmap(double, {1, 2, 3})
{2, 4, 6}
>>> fmap(double, {'a': 1, 'b': 2, 'c': 3})
{'a': 2, 'b': 4, 'c': 6}
>>> fmap(double, 'double')
'ddoouubbllee'
>>> Point = namedtuple('Point', ['x', 'y', 'z'])
>>> fmap(double, Point(x=1, y=2, z=3))
Point(x=2, y=4, z=6)
A final note on breaking interfaces
Neither of these approaches can guarantee that this will work for all things recognized as Sequences, and so on, because the ABC mechanism doesn't check function signatures. This is a problem not only for constructors, but also for all other methods. And it's unavoidable without type annotations.
In practice, however, it probably doesn't matter much. If you find yourself using a tool that breaks interface conventions in weird ways, consider using a different tool. (I'd actually say that goes for namedtuples too, as much as I like them!) This is the "consenting adults" philosophy behind many Python design decisions, and it has worked pretty well for the last couple of decades.
I am using python's set class. The set contains tuples (id,name). Given an id how can I check whether that corresponds to one already in the set and do:
if id is not in the set by searching the tuples
add a new tuple (id,name) in the set
I am using sets because they are supposed to use a hashtable which is more efficient than a list and I am dealing with a lot of data (more than 50GB)
You'll have to loop over all tuples in the set and test each one:
if not any(t[0] == id for t in tuple_set):
tuple_set.add((id, some_name))
The any() function here will iterate over the generator expression given and short-circuit to return True as soon as a match is found.
If your tuples are always going to be unique based on the first element, then you probably want to use a custom class that implements __eq__ and __hash__:
class Entry(object):
__slots__ = ('id', 'name') # save some memory
def __init__(self, id, name):
self.id = id
self.name = name
def __eq__(self, other):
if not isinstance(other, Entry): return NotImplemented
return self.id == other.id
def __hash__(self):
return id(self.id)
def __repr__(self):
return '<{0}({1[0]!r}, {1[1]!r})>'.format(type(self).__name__, self)
def __getitem__(self, index):
return getattr(self, ('id', 'name')[index])
then use those in a set, after which you can use:
if Entry(id, some_name) in entries_set:
Demo:
>>> entries_set = {Entry('foo', 'bar'), Entry('foo', 'baz')}
>>> entries_set
set([<Entry('foo', 'baz')>])
>>> Entry('foo', 'spam') in entries_set
True
Another option is to just map ids to names in a dictionary; dictionaries are sets with values:
id_value_dictionary = {'id1': 'name1', 'id2': 'name2'}
if id not in id_value_dictionary:
id_value_dictionary[id] = some_name
in Python set and dict use a very similar implementation:
Python collections complexity
And they're both backed by an hashtable.
What you'd like to do is not suitable to set; use a dict with "id" as key and "name" as value, and use the setdefault method:
#!/usr/bin/python
d = {"a": 1, "b": 2, "c": 3}
d.setdefault("a", 5) # a will retain its original value
d.setdefault("d", 9) # the d key will be inserted with the passed value
In order to get the key-value tuples as you'd like, you can use the items() or iteritems() methods (which one depends on your requirements, the first creates a list, the second an iterable; the latter is probably better for very large datasets as it uses less memory).
Imagine I have the following Traits objects:
from traits.api import Int, HasTraits, Instance
class Foo(HasTraits):
a = Int(2)
b = Int(5)
class Bar(HasTraits):
c = Int(7)
foo = Instance(Foo,())
Bar will let me access attribute a on Foo via:
bar = Bar()
bar.foo.a
>>> 2
Is there a standard way to return bar as a nested dictionary of the form:
print bar_as_dict
>>> {'c':7, 'foo':{'a':2, 'b':5}}
I'm essentially trying to extract all subtraits on an object that are a particular type. Our use case is we have deeply-nested HasTrait objects that have plot traits, and we are trying to dynamically find all the plots on a particular object. We have a function that can return the plots from a nested dictionary, but we need to pass HasTrait objects in, so formatting them into nested dictionaries would be great. If there is another way to dynamically inspect the stack of a HasTraits object and return all traits of a certain type, that would work too.
Here's a link to the HasTraits API... couldn't figure this out directly from that.
Solution Attempt
I've tried using the .traits() method, but it returns these CTrait objects.
print bar.traits()
>>>{'trait_added': <traits.traits.CTrait object at 0x8b7439c>,
'c': <traits.traits.CTrait object at 0x8b29e9c>,
'foo': <traits.traits.CTrait object at 0x8b29e44>,
'trait_modified': <traits.traits.CTrait object at 0x8b74344>}
Which don't evaluate as I'd expect:
isinstance(bar.traits()['c'], int)
>>> False
But after Pieter's suggestion, this works:
print bar.traits()['c'].is_trait_type(Int)
>>> True
Now the question is how to do this recursively.
I figured it out after following a similar question on recursion of a nested dictionary without Trait values
def flatten_traitobject(traitobject, *types):
node_map = {}
node_path = []
def nodeRecursiveMap(traitobject, node_path):
for key in traitobject.editable_traits():
val = traitobject.get(key)[key]
for type in types:
if isinstance(val, types[0]):
node_map['.'.join(node_path + [key])] = val
try:
nodeRecursiveMap(val, node_path + [key])
except (AttributeError, TypeError):
pass
nodeRecursiveMap(traitobject, node_path)
return node_map
Testing it out, I can choose to retain only integers and/or only objects of type Foo
bar=Bar()
print 'RETAINING ONLY INTEGER TYPES'
print flatten_traitobject(bar, int)
print '\nRETAINTING ONLY FOO OBJECT TYPES'
print flatten_traitobject(bar, Foo)
>>> RETAINING ONLY INTEGER TYPES
>>> {'c': 7, 'foo.b': 5, 'foo.a': 2}
>>> RETAINTING ONLY FOO OBJECT TYPES
>>> {'foo': <__main__.Foo object at 0x8f9308c>}
Foo represents the special plotting traits I'm after, so I can effectively return them now.
The built-in vars(obj) returns a dict with key/values mirroring the attributes of obj. Is there an inverse of this function? I.e. a function that takes a dictionary and returns an object.
I've come up with two ways of doing it, neither of which would be obvious to someone reading it. The first version involves assigning a new dict to self.__dict__:
class _Tmp(object):
def __init__(self, dct):
self.__dict__ = dct
obj = _Tmp({'hello': 'world'})
assert obj.hello == 'world'
and the second version uses a non-standard call to the type builtin:
obj = type('', (), {'hello': 'world'})
assert obj.hello == 'world'
Is there an easier/more readable way?
In Python 3.3 and up you can use types.SimpleNamespace:
from types import SimpleNamespace
obj = SimpleNamespace(**{'hello': 'world'})
There is the module attrdict that does what you want.