How to overload python sets to accept duplicates? - python-3.x

I had taken a python coding test, which asked to create a class that overloads the builtin set(all the methods of sets must work). The only change between the set I was asked to create and the builtin sets is that my custom sets SHOULD store duplicates, and 2 more custom methods.
Here is what I could come up with:
import builtins
class Multiset(builtins.set):
def __init__(self):
super().__init__()
self.my_set = builtins.set()
def add(self, val):
self.my_set.add(val)
def remove(self, val):
# removes one occurrence of val from the multiset, if any
self.my_set.discard(val)
def __contains__(self, val):
# returns True when val is in the multiset, else returns False
return val in self.my_set
def __len__(self):
# returns the number of elements in the multiset
return len(self.my_set)
I have tried overriding multiple methods, but to no avail. I also couldn't find a method that defined this non-duplicate criteria for sets. So, how do I do this?
EDIT 1:
Here is the problem description, if you want to see it.

You can use a dictionary which maps objects to a list of all objects that are equal to themselves. The advantage is that dict keys are already set-like.
from collections import defaultdict
class MultiSet:
def __init__(self):
self._items = defaultdict(list)
def add(self, item):
self._items[item].append(item)
def remove(self, item):
try:
self._items[item].remove(item)
except ValueError:
pass
def __contains__(self, item):
return item in self._items
def __len__(self):
return sum(len(v) for v in self._items.values())

Related

How could I create a docstring decorator in the presence of properties?

I have a collection of ever more specialized classes which correspond to collections of the same kind of data (temperature, density, etc) but for different drifts, for example, one subclass has dimensions (nx, ny) and a different suclass has dimensions (ncv), and I want to reflect that in the docstrings, for having a better documentation using Sphinx.
After reading many very useful threads here in Stack Overflow, I have arrived to this model:
import numpy as np
from functools import wraps
def class_decorator(cls):
import ipdb; ipdb.set_trace()
clsdict = {}
mro = cls.mro()
mro.reverse()
for tmp in mro[1:]: ##Ignore object class parent.
clsdict.update(tmp.__dict__)
for name, method in clsdict.items():
if hasattr(method, '__og_doc__'):
try:
method.__doc__ = method.__og_doc__.format(**clsdict)
except:
pass
else:
try:
method.__og_doc__ = method.__doc__
method.__doc__ = method.__doc__.format(**clsdict)
except:
pass
return cls
def mark_documentation(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
return wrapped
def documented_property(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
prp= property(wrapped)
prp.__og_doc__ = fn.__og_doc__
return prp
#class_decorator
class Base(object):
_GRID_DIM = 'nx, ny'
_TYPE = 'BaseData'
def __init__(self, name):
self.name = name
def shape(self):
""" This docstring contains the type '{_TYPE}' of class."""
print('Simple')
def operation(self, a, b, oper=np.sum, **kwargs):
""" Test for functions with args and kwargs in {_TYPE}"""
return oper([a,b])
#classmethod
def help(cls, var):
try:
print(get(cls, var).__doc__)
except:
print("No docstring yet.")
#class_decorator
class Advanced(Base):
_GRID_DIM = 'ncv'
_TYPE = 'AdvancedData'
def __init__(self,name):
super().__init__(name)
#property
#mark_documentation
# #documented_property
def arkansas(self):
"""({_GRID_DIM}, ns): Size of Arkansaw."""
return 'Yeah'
I am aiming to get the correctly formatted docstring when I call the help method or I use Sphinx, so that:
> adv = Advanced('ADV')
> adv.help("arkansas")
(ncv, ns): Size of Arkansaw.
> adv.help("operation")
Test for functions with args and kwargs in AdvancedData
I have managed to make it work so far, except for properties, because I assigned __og_doc__ to the function, but the property does not have that attribute. My last attempt at monkeypatching this, documented_property, fails because property is inmutable (as expected), and I cannot come up with any way to avoid this roadblock.
Is there any way around this problem?

Creating a child class from a parent method in python

I am trying to make a class that has a bunch of children that all have their own respective methods but share common methods through the parent. The problem is I need to create an instance of the child class in the parent method but am not sure how to go about it
my code so far looks like this
def filterAttribute(self, attribute, value):
newlist = []
for thing in self._things:
if thing._attributes[attribute] == value:
newlist.append(thing)
return self.__init__(newlist)
the class constructor takes in a list as its sole argument. Does anyone know if there is a standard way of doing this because my code is returning a NoneType object
Here are a few examples of classes I have made
This is the parent class:
class _DataGroup(object):
def __init__(self, things=None):
self._things=things
def __iter__(self):
for x in self._things:
yield x
def __getitem__(self, key):
return self._things[key]
def __len__(self):
return len(self._things)
def extend(self, datagroup):
if(isinstance(datagroup, self.__class__)):
self._things.extend(datagroup._things)
self._things = list(set(self._things))
def filterAttribute(self, attribute, value):
newlist = []
for thing in self._things:
if thing._attributes[attribute] == value:
newlist.append(thing)
#return self.__init__(newlist)
return self.__init__(newlist)
this is one of the child classes
class _AuthorGroup(_DataGroup):
def __init__(self, things=None):
self._things = things
def getIDs(self):
return [x.id for x in self._things]
def getNames(self):
return [x.name for x in self._things]
def getWDs(self):
return [x.wd for x in self._things]
def getUrns(self):
return [x.urn for x in self._things]
def filterNames(self, names, incl_none=False):
newlist = []
for thing in self._things:
if((thing is not None or (thing is None and incl_none)) and thing.name in names):
newlist.append(thing)
return _AuthorGroup(newlist)
The functionality I am looking for is that I can use the parent class's with the child classes and create instances of the child classes instead of the overall DataGroup parent class
So if I correctly understand what you are trying to accomplish:
You want a Base Class 'DataGroup' which has a set of defined attributes and methods;
You want one or mpore child classes with the ability to inherit both methods and attributes from the base class as well as have the ability to over-ride base class methjods if necessary: and
You want to invoke the child class without also having to manually invoke the base class.
If this in fact is your problem, this is how I would proceed:
Note: I have modified several functions, since I think you have several other issues with your code, for example in the base class self._things is set up as a list, but in the functions get_item and filterAttribute you are assuming self._things is a dictionary structure. I have modified the functions so all assume a dict structure for self._things
class _DataGroup:
def __init__(self, things=None):
if things == None:
self._things = dict() #Sets up default empty dict
else:
self._things=things
def __iter__(self):
for x in self._things.keys():
yield x
def __len__(self):
return len(self._things)
def extend(self, datagroup):
for k, v in datagroup.items():
nv = self._things.pop(k, [])
nv.append(v)
self._things[k] = nv
# This class utilizes the methods and attributes of DataGroup
# and adds new methods, unique to the child class
class AttributeGroup(_DataGroup):
def __init__(self, things=None):
super.__init__(things)
def getIDs(self):
return [x for x in self._things]
def getNames(self):
return [x.name for x in self._things]
def getWDs(self):
return [x.wd for x in self._things]
def getUrns(self):
return [x.urn for x in self._things]
# This class over-rides a DataGroup method and adds new attribute
class NewChild(_DataGroup):
def __init__(self, newAttrib, things = None):
self._newattrib = newAttrib
super.__init__(self, things)
def __len__(self):
return max(len(self._newattrib), len(self._things))
These examples are simplified, since I am not absolutely sure of what you really want.

How to work with a python collections.deque of custom class instances?

I am trying to utilize python deque from collections module where the element inside the deque is a custom class instances. I want to know how I can erase/delete an object? Can I use the builtin methods like deque.remove(element) if yes, how? How would it find my custom object?
class Buffer(object):
""" """
def __init__(self, name, size_total, size_in_cache):
self.name = name
self.size_total = size_total
class Storage(object):
"""
"""
def __init__(self, capacity):
self.CAPACITY = capacity
self.contents = collections.deque()
self.capacity_used = 0
def push_to_contents(self, buffer_name, buffer_size):
buf = Buffer(buffer_name, buffer_size)
self.contents.appendleft(buf)
def delete_from_contents(self, buffer_name)
""" HOW??
How can I use self.contents.remove() here>
"""
The way collections.deque.remove operates is by comparing the argument to each item in the deque. If it finds something which is equal to the argument, it removes it. Otherwise, it raises a ValueError.
Since a Buffer object, as you've implemented it, doesn't know how to compare itself with other objects, Python defaults (using the object parent class) to comparing the id values.
However, if you were to implement the __eq__ method for your class, you could accomplish what you're looking for.
E.g.,
def __eq__(self, other):
if isinstance(other, Buffer):
return self.name == other.name and self.size_total == other.size_total
elif isinstance(other, str):
return self.name == other
else:
return NotImplemented
EDIT:
This is all fine and good if you're using Python 3. In Python 2, you have to implement __ne__ ("not equal") as well. It can be as simple as
def __ne__(self, other):
return not self == other
Python 3 takes care of this for you automatically.

Create a list that can be accessed from multiple classes

I'm trying to create a list that is populated in one class and read in another class. I have a number of things, right now I'm getting the error shown below. I show only one class where the list is read, but there will be others.
How do I do this?
ReadDatabase.py
class ReadDatabase(object):
f_type_list = ReadDatabase.getFTypes() ## 'ReadDatabase' not defined
#staticmethod
def getFTypes():
<reads from database>
return my_list
MyTreeView.py
from ReadDatabase import *
class MyTreeView (ttk.Treeview):
def __init__(self, frame=None, list=[], column_headers=[]):
for f_type in ReadDatabase.f_type_list:
<do stuff>
You can separate it into two different classes in two different ways.
Example 1: Using two classes, one class (A) creates & updates the list and the other class (B) creates an instance of A and controls it:
class A:
"""
Create and updates the list
"""
def __init__(self):
self.my_list = []
self._read_from_database()
def _read_from_database(self):
# some database update logic
self.my_list.append(3)
class B:
"""
Creates an instance of A and can read from it.
"""
def __init__(self):
self.a = A()
def print_list(self):
for index, element in enumerate(self.a.my_list):
print(f"Index: {index} Element: {element}")
b_object = B()
b_object.print_list() # Prints: Index: 0 Element: 3
or
Example 2: You can just create a method in class B and just pass it the lst from class A:
class A:
"""
Create and updates the list
"""
def __init__(self):
self.my_list = []
self._read_from_database()
def _read_from_database(self):
# some database update logic
self.my_list.append(3)
class B:
def __init__(self):
pass
def print_list(self, lst):
for index, element in enumerate(lst):
print(f"Index: {index} Element: {element}")
a_object = A()
b_object = B()
b_object.print_list(a_object.my_list)
You can also pass the entire instance of A to B for it to use if you wanted to do it that way.

call special function when DataFrame is called upon custom class

I have the following classes:
class Result(UserDict):
"""Implements a especial version of dictionary, that will return the keys
ordered in the initialized way"""
def __init__(self, keys_order, items):
super().__init__(self)
self.__keys_order = keys_order
self.data = items
def __repr__(self):
attributes = ["{}:{}".format(_stringify(k), _stringify(self.data[k])) for k in self.keys()]
return "{}".format(", ".join(attributes))
def keys(self):
return [key for key in self.__keys_order]
class Results(UserList):
"""Implements a especial kind of list, that has a method to_df"""
def to_df(self):
return pd.DataFrame(self.data, columns=self.data[0].keys())
In this way, when I print an instance of Result, it will show it with the keys in the desired way (determined by keys_order). Also, the class Results implements the method to_df, which returns a pandas DataFrame with the columns ordered by the keys.
I know for example that if I want the len(results) function to behave in a especial way, I have to implement the __len__ method in it, in a similar way, is it possible to implement a special method so when pd.DataFrame(results) is called upon a results instance it will call to_df method instead? so I have the columns ordered by the keys.
You could have your Result class inherit not just from UserDict but also from pd.DataFrame. Then you just have to define the _data attribute of your class to be what you want the class to hand to pd.DataFrame(), i.e. the pd.DataFrame that you want to be constructed.
class Result(UserDict, pd.DataFrame):
"""Implements a especial version of dictionary, that will return the keys
ordered in the initialized way"""
def __init__(self, keys_order, items):
super().__init__(self)
self.__keys_order = keys_order
self.data = items
self._data = pd.DataFrame(self.data, columns=self.data[0].keys())
This becomes evident when looking at the source code of the pd.DataFrame class:
def __init__(self, data=None, index=None, columns=None, dtype=None,
copy=False):
if data is None:
data = {}
if dtype is not None:
dtype = self._validate_dtype(dtype)
if isinstance(data, DataFrame):
data = data._data
upon calling the __init__ method, which is what you are effectively doing when you use pd.DataFrame(results), it will check if results is an instance of DataFrame. If it is, then it will just set data to be results._data. Alternatively your results class could also inherit from dict, in which case the dict constructor would be called inside the __init__:
elif isinstance(data, dict):
mgr = self._init_dict(data, index, columns, dtype=dtype)
Here the excerpt from self._init_dict that would be called in your case:
else:
keys = list(data.keys())
if not isinstance(data, OrderedDict):
keys = _try_sort(keys)
columns = data_names = Index(keys)
arrays = [data[k] for k in keys]
So you have to define a keys() method for your class that returns the keys (which you already have), as well as __getitem__, so that data[k] in the last line returns the values of column k.

Resources