This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 3 years ago.
Why am I getting the previous value into the different instance variables?
For example:
d1 = myDict()
d2 = myDict()
d1.assign(2,3)
d2.assign(2,2)
print(d1.getval(2))
print(d2.getval(2))
class myDict(object):
""" Implements a dictionary without using a dictionary """
aDict = {}
def __init__(self):
""" initialization of your representation """
#FILL THIS IN
def assign(self, k, v):
""" k (the key) and v (the value), immutable objects """
#FILL THIS IN
self.k = k
self.v = v
if self.k not in myDict.aDict:
self.aDict[self.k] = self.v
else:
self.aDict[self.k] = self.v
def getval(self, k):
""" k, immutable object """
#FILL THIS IN
if k in myDict.aDict:
return myDict.aDict[k]
else:
KeyError ('KeyError successfully raised')
# return myDict.aDict[k]
def delete(self, k):
""" k, immutable object """
#FILL THIS IN
if k in myDict.aDict.keys():
del myDict.aDict[k]
else:
raise KeyError('KeyError successfully raised')
def __str__(self):
return str(myDict.aDict)
d1 = myDict()
d2 = myDict()
d1.assign(2,3)
d2.assign(2,2)
print(d1.getval(2))
print(d2.getval(2))
My output:
2
2
4
1
Correct output:
3
2
4
1
aDict has been defined as a class level attribute, this means that all instances of myDict will share the same aDict.
To assign a separate aDict for each instance you should do this in the __init__ method
def __init__(self):
self.aDict = {}
It looks like aDict is not an instance variable, but a static variable. This means there exists only one aDict instance on a class-level which is shared by all instances of your myDict class. As a result, any changes you make to aDict in any given myDict instance will be reflected in all myDict instances.
In addition, I'd like to point out that you're not following the instructions of the assignment. The docstring of your class says you must implement this class without using a dictionary.
Related
I want to create multiple objects and I want each object to keep track of the order it was created, so first object has id of 1, second id of 2 and so on.
class Something:
id=0
def __init__(self):
Something.id+=1
Currently I managed to keep track of the instances but not order. So
something1=Something()
something2=Something()
and if I call the id, both return 2
In this case, the reason that both of the classes return an id of 2 is because you are incrementing the class variable instead of an instance specific variable.
You can instead make use of both to get proper ids, i.e. the following:
class Something:
id=0
def __init__(self):
Something.id+=1
self.id = Something.id
something1=Something()
something2=Something()
print(something1.id, something2.id)
(this prints 1 2). The value of Something.id (the class variable) is also 2 in this case.
Basically what you need is the class to count the number of instances of itself that are created, which could be used to set the value of an instance id attribute. The counting itself can be accomplished by applying the built-in next() function to an itertools.count() iterator object.
Also, since it's possible you may want to add this capability to multiple classes, implementing the instance-counting in a metaclass would make sense since doing so would allow it to easily be reused. Using a metaclass also insures that subclasses — i.e. class SomethingElse(Something): — will each have their own separate instance counters (instead of them all sharing the one in the baseclass as it would be in most of the other answers so far).
Here's what I'm suggesting:
from itertools import count
class InstanceCounterMeta(type):
"""Metaclass to maintain an instance count."""
def __init__(cls, name, bases, attrs):
super().__init__(name, bases, attrs)
cls._instance_count = count(start=1)
class Something(metaclass=InstanceCounterMeta):
def __init__(self):
self.id = next(self._instance_count)
something1 = Something()
something2 = Something()
print(something1.id) # -> 1
print(something2.id) # -> 2
Just create an id member that isn't static:
class Something:
id = 0
def __init__(self):
Something.id += 1;
self.id = Something.id
something1 = Something()
something2 = Something()
print(something1.id) # Prints 1
print(something2.id) # Prints 2
If the goal of Something is more than keeping track of the instances you can separate this task and make it independently of it. The globals() built-in function is a dictionary which contains key-pair of "identifier-object". It is a dictionary so the insertion order is respected.
Note that it returns the state of when it is called, so if some objects are deleted they will not appear in the globals().
class A: pass
a1 = A()
a3 = A()
a2 = A()
# amount of instances
len(tuple(obj for obj in globals().values() if isinstance(obj, A)))
# 3
# object identifiers at this state of the program
(tuple(k for k, v in globals().items() if isinstance(v, A)))
# ('a1', 'a3', 'a2')
# delete an object
del a1
# new state
(tuple(k for k, v in globals().items() if isinstance(v, A)))
('a3', 'a2')
EDIT - implemented as class method
class A:
#classmethod
def instance_counter(cls):
n = len(tuple(obj for obj in globals().values() if isinstance(obj, cls)))
objs = ', '.join(tuple(k for k, v in globals().items() if isinstance(v, cls)))
print(f'"{n}" instances of {cls.__name__} are in use: "{objs}"')
a1 = A()
a3 = A()
a2 = A()
A.instance_counter()
#"3" instances of A are in use: "a1, a3, a2"
I was clear how dictionaries work in Python until I found this logic.
class Sample:
__test = {}
def __init__(self):
self.__dict__ = self.__test
self.key = "answer"
self.count = "numbers"
def print_test(self):
print(self.__test)
s = Sample()
s.print_test()
In the above code a dictionary is initialized and then same variable is assigned to the class dict. In the next line we are initializing 2 more variables to the class.
In the end we are initializing Sample class to an "s object"
As per my understanding this should be following output and __test dictionary should be empty
s.count = "numbers"
s.key = "answers"
But to my surprise the print_test functions returns
{'count': 'numbers', 'key': 'answer'}
Can anyone explain how the __test dictionary got these items as key value pairs.
The __init__ function runs sequentially. When you set self.__dict__ = self.__test, you assign the object's internal state dictionary to be empty. However, when you next set the values of self.key and self.count, those attributes are added to the now empty self.__dict__, and by mutual assignment, to self.__test
You can see the difference you assign the empty dict at the end of the __init__ method.
class Sample:
__test = {}
def __init__(self):
self.key = "answer"
self.count = "numbers"
self.__dict__ = self.__test
def print_test(self):
print(self.__test)
s = Sample()
s.print_test()
# prints:
{}
My problem can be divide in two parts. The first one is not allow more two equal values in the dictionary. For example, I have this class:
class MyClass():
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __key(self):
return tuple(self.__dict__[key] for key in self.__dict__)
def __eq__(self, other):
if isinstance(other, type(self)):
return self.__key() == other.__key()
return NotImplemented
And I want to create and stored many objects in a dictionary like this
if __name__ == '__main__':
obj1 = MyClass(1, 2, 3)
obj2 = MyClass(3, 4, 5)
obj3 = MyClass(1, 2, 3)
myDict = {} # empty dictionary
myDict['a'] = obj1 # one key-value item
myDict['b'] = obj2 # two key-value items
myDict['c'] = obj3 # not allowed, value already stored
How to be sure that obj3 can't be stored in the dictionary ?
The second part of my problem is track when a mutable object change to avoid it be equal to the other values in the dictionary, i.e.:
obj2.a = 1; obj2.b = 2; obj2.c = 3 # not allowed
I coded a class Container that inherit from the dictionary class, to store the values (with uniques keys), and I added a set, to track the values in the dictionary, i.e.:
class MyContainer(dict):
def __init__(self):
self.unique_objects_values = set()
def __setitem__(self, key, value):
if key not in self: # overwrite not allowed
if value not in self.unique_object_values: # duplicate objects values don't allowed
super(MyContainer, self).__setitem__(key, value)
self.unique_object_values.add(value)
else:
print("Object already exist. Object didn't stored")
else:
print("Key already exist. Object didn't stored")
And add parent member to MyClass to check if the values aren't already stored but I'm not pretty sure if a data structure already exist to solve my problem.
Make another dictionary of the valued elements and check before adding the values to the original dictionary if it is present then don't add.
While looking over some code in Think Complexity, I noticed their Graph class assigning values to itself. I've copied a few important lines from that class and written an example class, ObjectChild, that fails at this behavior.
class Graph(dict):
def __init__(self, vs=[], es=[]):
for v in vs:
self.add_vertex(v)
for e in es:
self.add_edge(e)
def add_edge(self, e):
v, w = e
self[v][w] = e
self[w][v] = e
def add_vertex(self, v):
self[v] = {}
class ObjectChild(object):
def __init__(self, name):
self['name'] = name
I'm sure the different built in types all have their own way of using this, but I'm not sure whether this is something I should try to build into my classes. Is it possible, and how? Is this something I shouldn't bother with, relying instead on simple composition, e.g. self.l = [1, 2, 3]? Should it be avoided outside built in types?
I ask because I was told "You should almost never inherit from the builtin python collections"; advice I'm hesitant to restrict myself to.
To clarify, I know that ObjectChild won't "work", and I could easily make it "work", but I'm curious about the inner workings of these built in types that makes their interface different from a child of object.
In Python 3 and later, just add these simple functions to your class:
class some_class(object):
def __setitem__(self, key, value):
setattr(self, key, value)
def __getitem__(self, key):
return getattr(self, key)
They are accomplishing this magic by inheriting from dict. A better way of doing this is to inherit from UserDict or the newer collections.MutableMapping
You could accomplish a similar result by doing the same:
import collections
class ObjectChild(collections.MutableMapping):
def __init__(self, name):
self['name'] = name
You can also define two special functions to make your class dictionary-like: __getitem__(self, key) and __setitem__(self, key, value). You can see an example of this at Dive Into Python - Special Class Methods.
Disclaimer : I might be wrong.
the notation :
self[something]
is legit in the Graph class because it inherits fro dict. This notation is from the dictionnaries ssyntax not from the class attribute declaration syntax.
Although all namespaces associated with a class are dictionnaries, in your class ChildObject, self isn't a dictionnary. Therefore you can't use that syntax.
Otoh, in your class Graph, self IS a dictionnary, since it is a graph, and all graphs are dictionnaries because they inherit from dict.
Is using something like this ok?
def mk_opts_dict(d):
''' mk_options_dict(dict) -> an instance of OptionsDict '''
class OptionsDict(object):
def __init__(self, d):
self.__dict__ = d
def __setitem__(self, key, value):
self.__dict__[key] = value
def __getitem__(self, key):
return self.__dict__[key]
return OptionsDict(d)
I realize this is an old post, but I was looking for some details around item assignment and stumbled upon the answers here. Ted's post wasn't completely wrong. To avoid inheritance from dict, you can make a class inherit from MutableMapping, and then provide methods for __setitem__ and __getitem__.
Additionally, the class will need to support methods for __delitem__, __iter__, __len__, and (optionally) other inherited mixin methods, like pop. The documentation has more info on the details.
from collections.abc import MutableMapping
class ItemAssign(MutableMapping):
def __init__(self, a, b):
self.a = a
self.b = b
def __setitem__(self, k, v):
setattr(self, k, v)
def __getitem__(self, k):
getattr(self, k)
def __len__(self):
return 2
def __delitem__(self, k):
self[k] = None
def __iter__(self):
yield self.a
yield self.b
Example use:
>>> x = ItemAssign("banana","apple")
>>> x["a"] = "orange"
>>> x.a
'orange'
>>> del x["a"]
>>> print(x.a)
None
>>> x.pop("b")
'apple'
>>> print(x.b)
None
Hope this serves to clarify how to properly implement item assignment for others stumbling across this post :)
Your ObjectChild doesn't work because it's not a subclass of dict. Either of these would work:
class ObjectChild(dict):
def __init__(self, name):
self['name'] = name
or
class ObjectChild(object):
def __init__(self, name):
self.name = name
You don't need to inherit from dict. If you provide setitem and getitem methods, you also get the desired behavior I believe.
class a(object):
def __setitem__(self, k, v):
self._data[k] = v
def __getitem__(self, k):
return self._data[k]
_data = {}
Little memo about <dict> inheritance
For those who want to inherit dict.
In this case MyDict will have a shallow copy of original dict in it.
class MyDict(dict):
...
d = {'a': 1}
md = MyDict(d)
print(d['a']) # 1
print(md['a']) # 1
md['a'] = 'new'
print(d['a']) # 1
print(md['a']) # new
This could lead to problem when you have a tree of nested dicts and you want to covert part of it to an object. Changing this object will not affect its parent
root = {
'obj': {
'a': 1,
'd': {'x': True}
}
}
obj = MyDict(root['obj'])
obj['a'] = 2
print(root) # {'obj': {'a': 1, 'd': {'x': True}}} # 'a' is the same
obj['d']['x'] = False
print(root) # {'obj': {'a': 1, 'd': {'x': True}}} # 'x' chanded
I have written a custom container object.
According to this page, I need to implement this method on my object:
__iter__(self)
However, upon following up the link to Iterator Types in the Python reference manual, there are no examples given of how to implement your own.
Can someone post a snippet (or link to a resource), that shows how to do this?
The container I am writing, is a map (i.e. stores values by unique keys).
dicts can be iterated like this:
for k, v in mydict.items()
In this case I need to be able to return two elements (a tuple?) in the iterator.
It is still not clear how to implement such an iterator (despite the several answers that have been kindly provided). Could someone please shed some more light on how to implement an iterator for a map-like container object? (i.e. a custom class that acts like a dict)?
I normally would use a generator function. Each time you use a yield statement, it will add an item to the sequence.
The following will create an iterator that yields five, and then every item in some_list.
def __iter__(self):
yield 5
yield from some_list
Pre-3.3, yield from didn't exist, so you would have to do:
def __iter__(self):
yield 5
for x in some_list:
yield x
Another option is to inherit from the appropriate abstract base class from the `collections module as documented here.
In case the container is its own iterator, you can inherit from
collections.Iterator. You only need to implement the next method then.
An example is:
>>> from collections import Iterator
>>> class MyContainer(Iterator):
... def __init__(self, *data):
... self.data = list(data)
... def next(self):
... if not self.data:
... raise StopIteration
... return self.data.pop()
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
... print i
...
...
4.0
3
two
1
While you are looking at the collections module, consider inheriting from Sequence, Mapping or another abstract base class if that is more appropriate. Here is an example for a Sequence subclass:
>>> from collections import Sequence
>>> class MyContainer(Sequence):
... def __init__(self, *data):
... self.data = list(data)
... def __getitem__(self, index):
... return self.data[index]
... def __len__(self):
... return len(self.data)
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
... print i
...
...
1
two
3
4.0
NB: Thanks to Glenn Maynard for drawing my attention to the need to clarify the difference between iterators on the one hand and containers that are iterables rather than iterators on the other.
usually __iter__() just return self if you have already define the next() method (generator object):
here is a Dummy example of a generator :
class Test(object):
def __init__(self, data):
self.data = data
def next(self):
if not self.data:
raise StopIteration
return self.data.pop()
def __iter__(self):
return self
but __iter__() can also be used like this:
http://mail.python.org/pipermail/tutor/2006-January/044455.html
The "iterable interface" in python consists of two methods __next__() and __iter__(). The __next__ function is the most important, as it defines the iterator behavior - that is, the function determines what value should be returned next. The __iter__() method is used to reset the starting point of the iteration. Often, you will find that __iter__() can just return self when __init__() is used to set the starting point.
See the following code for defining a Class Reverse which implements the "iterable interface" and defines an iterator over any instance from any sequence class. The __next__() method starts at the end of the sequence and returns values in reverse order of the sequence. Note that instances from a class implementing the "sequence interface" must define a __len__() and a __getitem__() method.
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, seq):
self.data = seq
self.index = len(seq)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> next(rev) # note no need to call iter()
'm'
>>> nums = Reverse(range(1,10))
>>> next(nums)
9
If your object contains a set of data you want to bind your object's iter to, you can cheat and do this:
>>> class foo:
def __init__(self, *params):
self.data = params
def __iter__(self):
if hasattr(self.data[0], "__iter__"):
return self.data[0].__iter__()
return self.data.__iter__()
>>> d=foo(6,7,3,8, "ads", 6)
>>> for i in d:
print i
6
7
3
8
ads
6
To answer the question about mappings: your provided __iter__ should iterate over the keys of the mapping. The following is a simple example that creates a mapping x -> x * x and works on Python3 extending the ABC mapping.
import collections.abc
class MyMap(collections.abc.Mapping):
def __init__(self, n):
self.n = n
def __getitem__(self, key): # given a key, return it's value
if 0 <= key < self.n:
return key * key
else:
raise KeyError('Invalid key')
def __iter__(self): # iterate over all keys
for x in range(self.n):
yield x
def __len__(self):
return self.n
m = MyMap(5)
for k, v in m.items():
print(k, '->', v)
# 0 -> 0
# 1 -> 1
# 2 -> 4
# 3 -> 9
# 4 -> 16
In case you don't want to inherit from dict as others have suggested, here is direct answer to the question on how to implement __iter__ for a crude example of a custom dict:
class Attribute:
def __init__(self, key, value):
self.key = key
self.value = value
class Node(collections.Mapping):
def __init__(self):
self.type = ""
self.attrs = [] # List of Attributes
def __iter__(self):
for attr in self.attrs:
yield attr.key
That uses a generator, which is well described here.
Since we're inheriting from Mapping, you need to also implement __getitem__ and __len__:
def __getitem__(self, key):
for attr in self.attrs:
if key == attr.key:
return attr.value
raise KeyError
def __len__(self):
return len(self.attrs)
One option that might work for some cases is to make your custom class inherit from dict. This seems like a logical choice if it acts like a dict; maybe it should be a dict. This way, you get dict-like iteration for free.
class MyDict(dict):
def __init__(self, custom_attribute):
self.bar = custom_attribute
mydict = MyDict('Some name')
mydict['a'] = 1
mydict['b'] = 2
print mydict.bar
for k, v in mydict.items():
print k, '=>', v
Output:
Some name
a => 1
b => 2
example for inhert from dict, modify its iter, for example, skip key 2 when in for loop
# method 1
class Dict(dict):
def __iter__(self):
keys = self.keys()
for i in keys:
if i == 2:
continue
yield i
# method 2
class Dict(dict):
def __iter__(self):
for i in super(Dict, self).__iter__():
if i == 2:
continue
yield i