How to add a set of multiple values to a key? - python-3.x

I created a class which is basically a hobby book. The book can be accessed by two methods, enter(n,h) which takes a name and keep adding hobbies to that name(one name can have multiple hobbies). The other method returns a set of hobbies for a particular name. My hobby book is storing every hobby that I insert to one name. Can someone help me fixing it?
class Hobby:
def __init__(self):
self.dic={}
self.hby=set()
def enter(self,n,h):
if n not in self.dic.items():
self.dic[n]=self.hby
for k in self.dic.items():
self.hby.add(h)
def lookup(self,n):
return self.dic[n]
I tried running following cases
d = Hobby(); d.enter('Roj', 'soccer'); d.lookup('Roj')
{'soccer'}
d.enter('Max', 'reading'); d.lookup('Max')
{'reading', 'soccer'} #should return just reading
d.enter('Roj', 'music'); d.lookup('Roj')
{'reading', 'soccer','music'} #should return soccer and music

Why are you re-inventing a dict here? Why are you using a separate set to which you always add values, and reference it to every key which ensures that it always returns the same set on a lookup?
Don't reinvent the wheel, use collections.defaultdict:
import collections
d = collections.defaultdict(set)
d["Roj"].add("soccer")
d["Roj"]
# {'soccer'}
d["Max"].add("reading")
d["Max"]
# {'reading'}
d["Roj"].add("music")
d["Roj"]
# {'soccer', 'music'}
.
UPDATE - If you really want to do it through your own class (and before you do, watch Stop Writing Classes!), you can do it as:
class Hobby(object):
def __init__(self):
self.container = {}
def enter(self, n, h):
if n not in self.container:
self.container[n] = {h}
else:
self.container[n].add(h)
def lookup(self, n):
return self.container.get(n, None)
d = Hobby()
d.enter("Roj", "soccer")
d.lookup("Roj")
# {'soccer'}
d.enter("Max", "reading")
d.lookup("Max")
# {'reading'}
d.enter("Roj", "music")
d.lookup("Roj")
# {'soccer', 'music'}
Note how no extra set is used here - every dict key gets its own set to populate.

Related

Making vars() defined variables global in a function

I am running multiple scenarios for my experiment, which requires me to dynamically change the variable names depending upon the Scenario and Class. For that, I have got a few lines of working code, where changing simulations (i.e., Scenario and Class) changes the variable names. However, this code needs to be called everytime after I define my experiment. Code below:
# Funtion
def Moisture_transport(Scenario, Class, delta_crop):
""" (unrelated to this question) """
return Class_direct, Class_sum_cmr
""" Define the Scenario and Class """
Scenario = 2; Class = 1; delta_crop = True # Assign the Scenario, Class and delta_crop
## Few lines of code that needs to run every time without any change
if delta_crop == False:
vars()['Moisture_direct_Scenario_'+str(Scenario)+'_Class_'+str(Class)], vars()['Moisture_with_CMR_Scenario_'+str(Scenario)+'_Class_'+str(Class)] = Moisture_transport(Scenario, Class, delta_crop)
else:
vars()['Moisture_direct_Scenario_'+str(Scenario)+'_Class_'+str(Class)+'_deltacrop'], vars()['Moisture_with_CMR_Scenario_'+str(Scenario)+'_Class_'+str(Class)+'_deltacrop'] = Moisture_transport(Scenario, Class, delta_crop)
Does any one know how to make vars()['variable_name'] global in the function Moisture_transport?
I think this can be simpler still. There is some cost to handling a key so I'd not make them excessively long. Please note the global, where it is and is not used.
Moisture_variables = {}
def Moisture_transport(Scenario, Class, delta_crop):
global Moisture_variables
""" (unrelated to this question) """
#return Class_direct, Class_sum_cmr
Moisture_variables[f"{Scenario} {Class} {delta_crop}"] = (Class_direct, Class_sum_cmr)
You can also sub-dictionary the results although this creates a bit of overhead to checking if sub-dictionaries exist. Note I've deliberately changed (shortened) the variables in the called function to make it clear these are in a different scope.
Moisture_variables = {}
def Moisture_transport(Scenario, Class, delta_crop):
""" (unrelated to this question) """
#return Class_direct, Class_sum_cmr
add_Moisture_Variables(Scenario, Class, delta_crop, Class_direct, Class_sum_cmr)
def add_Moisture_variables(s, c, d, cd, cs):
global Moisture_variables
if s not in Moisture_variables:
Moisture_variables[s] = {}
if c not in Moisture_variables[s]:
Moisture_variables[s][c] = {}
Moisture_variables[s][c][d] = (cd, cs)
Yet another approach if a list works, the double bracket to append a tuple are important.
Moisture_variables = []
def Moisture_transport(Scenario, Class, delta_crop):
global Moisture_variables
""" (unrelated to this question) """
#return Class_direct, Class_sum_cmr
Moisture_variables.append((Scenario, Class, delta_crop, Class_direct, Class_sum_cmr))
The choice of which approach works best depends on how you wish to recover the data.
Defining a dictionary is more efficient in the following case to hold all the variables as string, which can be called with conditions, i.e., Scenario or Class.
#Add a last line to the original function
def Moisture_transport(Scenario, Class, delta_crop):
""" (unrelated to this question) """
#return Class_direct, Class_sum_cmr
variables_dict(Class_direct, Class_sum_cmr,delta_crop)
#Add a normal dictionary and a variable name defining funtion
Moisture_variables = {}
def variables_dict(Class_direct, Class_sum_cmr, delta_crop):
if delta_crop == False:
Moisture_variables['Moisture_direct_Scenario_{0}_Class_{1}'.format(Scenario,Class)] = Class_direct
Moisture_variables['Moisture_with_CMR_Scenario_{0}_Class_{1}'.format(Scenario,Class)] = Class_sum_cmr
else:
Moisture_variables['Moisture_direct_Scenario_{0}_Class_{1}_deltacrop'.format(Scenario,Class)] = Class_direct
Moisture_variables['Moisture_with_CMR_Scenario_{0}_Class_{1}_deltacrop'.format(Scenario,Class)] = Class_sum_cmr
After that, you can run the function Moisture_transport() as it is, and not worry about defining the variables outside the function, i.e., code after ## Few lines of code that needs to run every time without any change from the original question is not needed. E.g.:
""" Define the Scenario and Class """
Scenario = 1; Class = 0; delta_crop = False
Moisture_transport(Scenario, Class, delta_crop)

How to convert python dict to DictRow object

Hi I am writing unittest using pytest. But I am not able to mock few db functions. We are using psycopg2 for db connections and executions. Response of query returned from psycopg2 is of the type DictRow which can be accessed either by key or by index.
Ex:
response = ['prajwal', '23', 'engineer'] #Response of a query "select name, age , job from users"
>>>response[0]
'prajwal'
>>>response['name']
'prajwal'
I want to know is there any way by which we can covert dict/list to above mentioned type.
Looking at the source for psycopg2, creating a DictRow requires passing in a DictCursor object. However the only thing it uses from DictCursor appears to be an index and description attribute.
# found in lib\site-packages\psycopg2.extras.py
class DictRow(list):
"""A row object that allow by-column-name access to data."""
__slots__ = ('_index',)
def __init__(self, cursor):
self._index = cursor.index
self[:] = [None] * len(cursor.description)
The index looks like a dict with a mapping a key to an index. e.g.response['name'] = 0
The description looks like your dict that you want to convert.
If you're feeling hacky you could take advantage of duck typing and pretend you're passing in a cursor when you're just satisfying the requirements.
The only caveat is after we instantiate the DictRow, we need to populate it. Our fake cursor hack will take care of the rest.
from psycopg2.extras import DictRow
class DictRowHack:
def __init__(self, my_dict):
# we need to set these 2 attributes so that
# it auto populates our indexes
self.index = {key: i for i, key in enumerate(my_dict)}
self.description = my_dict
def dictrow_from_dict(my_dict):
# this is just a little helper function
# so you don't always need to go through
# the steps to recreate a DictRow
fake_cursor = DictRowHack(my_dict)
my_dictrow = DictRow(fake_cursor)
for k, v in my_dict.items():
my_dictrow[k] = v
return my_dictrow
response = {'name': 'prajwal', 'age': '23', 'job': 'engineer'}
my_dictrow = dictrow_from_dict(response)
print(my_dictrow[1])
print(my_dictrow['name'])
print(type(my_dictrow))

Best way to model JSON data in python

This question may be opinion based, but I figured I'd give it shot.
I am attempting to create a variety of classes which gets its values from JSON data. The JSON data is not under my control so I have to parse the data and select the values I want. My current implementation subclasses UserDict from python3's collection module. However, I have had iterations where I have directly created attributes and set the values to the parsed data.
The reason I changed to using the UserDict is the ease of using the update function.
However, I feel odd calling the object and using MyClass['attribute'] rather than MyClass.attribute
Is there a more pythonic way to model this data?
I am not 100% convinced that this makes sense, but you could try this:
class MyClass (object):
def __init__(self, **kwargs):
for key in kwargs.keys():
setattr(self, key, kwargs[key])
my_json = {"a":1, "b":2, "c":3}
my_instance = MyClass(**my_json)
print (my_instance.a)
# 1
print (my_instance.b)
# 2
print (my_instance.c)
# 3
--- edit
in case you have nested data you could also try this:
class MyClass (object):
def __init__(self, **kwargs):
for key in kwargs.keys():
if isinstance(kwargs[key],dict):
setattr(self, key, MyClass(**kwargs[key]))
else:
setattr(self, key, kwargs[key])
my_json = {"a":1, "b":2, "c":{"d":3}}
my_instance = MyClass(**my_json)
print (my_instance.a)
# 1
print (my_instance.b)
# 2
print (my_instance.c.d)
# 3

Trouble working with and updating dictionary using a class and function in Python 3 [Newbie]

I am somewhat new to coding. I have been self teaching myself for the past year or so. I am trying to build a more solid foundation and am trying to create very simple programs. I created a class and am trying to add 'pets' to a dictionary that can hold multiple 'pets'. I have tried changing up the code so many different ways, but nothing is working. Here is what I have so far.
# Created class
class Animal:
# Class Attribute
classes = 'mammal'
breed = 'breed'
# Initializer/Instance Attribrutes
def __init__ (self, species, name, breed):
self.species = species
self.name = name
self.breed = breed
# To get different/multiple user input
#classmethod
def from_input(cls):
return cls(
input('Species: '),
input('Name: '),
input('Breed: ')
)
# Dictionary
pets = {}
# Function to add pet to dictionary
def createpet():
for _ in range(10):
pets.update = Animal.from_input()
if pets.name in pets:
raise ValueError('duplicate ID')
# Calling the function
createpet()
I have tried to change it to a list and use the 'append' tool and that didn't work. I am sure there is a lot wrong with this code, but I am not even sure what to do anymore. I have looked into the 'collections' module, but couldn't understand it well enough to know if that would help or not. What I am looking for is where I can run the 'createpet()' function and each time add in a new pet with the species, name, and breed. I have looked into the sqlite3 and wonder if that might be a better option. If it would be, where would I go to learn and better understand the module (aka good beginner tutorials). Any help would be appreciated. Thanks!
(First of all, you have to check for a duplicate before you add it to the dictionary.)
The way you add items to a dictionary x is
x[y] = z
This sets the value with the key y equal to z or, if there is no key with that name, creates a new key y with the value z.
Updated code:
(I defined this as a classmethod because the from_input method is one as well and from what I understand of this, this will keep things working when it comes to inheriting classes, for further information you might want to look at this)
#classmethod
def createpet(cls):
pet = cls.from_input()
if pet.name in cls.pets:
raise ValueError("duplicate ID")
else:
cls.pets[pet.name] = pet

Iterating through class variables in python

Please correct my code
PS - i'm fairly new to python
class Contact:
def __init__(self,cid, email):
self.cid=cid
self.email=email
def ind(contacts):
index={}
#Code here
return index
contacts = [Contact(1,'a'),
Contact(2,'b'),
Contact(3,'c'),
Contact(4,'a')]
print(ind(contacts))
Need the output to be like -
{'a':[1,4], 'b':2, 'c':3}
The following methods create list values like:
{'a':[1,4], 'b':[2], 'c':[3]}
I can't imagine why this wouldn't be fine, but I've added a method at the end that gets your specific output.
This doesn't maintain order of the emails:
def ind(contracts):
index={}
for contract in contracts:
index.setdefault(contract.email, []).append(contract.cid)
return index
To maintain order (e.g. start with 'a'), add from collects import OrderedDict to the top of your file and then the method is:
def ind(contracts):
index = OrderedDict()
for contract in contracts:
index.setdefault(contract.email, []).append(contract.cid)
return index
The printout of index will look different, but it acts the same as a normal dict object (just with ordering).
Exact output (with ordering):
def ind(contracts):
index = OrderedDict()
for contract in contracts:
if contract.email in index:
value = index[contract.email]
if not isinstance(value, list):
index[contract.email] = [value]
index[contract.email].append(contract.cid)
else:
index[contract.email] = contract.cid
return index

Resources