Accessing dict from another module in Python - python

File1.py
john = {'fullname':'John Wick', 'Age': 35 , 'job':'Hitman'}
mark = {'fullname':'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'}
Will = {'fullname':'Will smith', 'Age': 45, 'job': 'Actor'}
so on... and many more names
So my question is how do I access the values, lets say I want to know the age of a person by giving the person's name?
File2.py
from File1.py import *
#what should the code be to access the age
#lets say I write 'john', I want to get his age
print john['Age'] # this is not how i want to access it
#
#any other way or methods ??
#
user_input=raw_input("enter a Name: ")
# user_input contains the name of the person I want to get the Age of

You can use a nested dictionary to pass the person's name to the dictionary and then access the age via the key "Age":
john = {'fullname':'John Wick', 'Age': 35 , 'job':'Hitman'}
mark = {'fullname':'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'}
Will = {'fullname':'Will smith', 'Age': 45, 'job': 'Actor'}
new_data = {"John":john, "Mark":mark, "Will":Will}
print(new_data["John"]["Age"])
Output:
35
Edit: Without a nested dictionary, you can try this:
john = {'fullname':'John Wick', 'Age': 35 , 'job':'Hitman'}
mark = {'fullname':'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'}
Will = {'fullname':'Will smith', 'Age': 45, 'job': 'Actor'}
user_input=raw_input("enter a Name: ")
final_age = [b["Age"] for a, b in globals().items() if a == user_input][0]
Output:
35

First of all in my opinion you should NOT do it like this. #Ajax1234 offers a much better solution, but to ask your question:
import File1
name = input('>>> Name: ')
print(getattr(File1, name)['Age']) # 35
Does it

You can use get function in dictionary
print(john.get('age' , 0))
get take two parameter first the key then the default value to load if key not found

You can use the built-in globals function. From documentation (emphasis mine):
Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
Edit:
As you are using separate files, you can create a function in the file File1.py that accepts the dictionary name and returns the appropriate value using the globals() function.
Usage:
File1.py
john = {'fullname':'John Wick', 'Age': 35 , 'job':'Hitman'}
mark = {'fullname':'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'}
Will = {'fullname':'Will smith', 'Age': 45, 'job': 'Actor'}
def get_age(person):
return globals()[person]['Age']
File2.py
import File1
person = input('Enter name:')
print(File1.get_age(person))

I don't fully understand why you are saving each of these dicts into a separate variable instead of just using a nested dict like
persons = {
'john': {'fullname': 'John Wick', 'Age': 35, 'job': 'Hitman'},
'mark': {'fullname': 'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'},
'will': {'fullname': 'Will Smith', 'Age': 45, 'job': 'Actor'}
}
with which you could use user input to access the persons dict's keys,
if you really want to name your variables based on their values (which does not make much sense to me since it's not really variable after), you can use Python's globals() and locals() function.
file1.py
john = {'fullname': 'John Wick', 'Age': 35, 'job': 'Hitman'}
mark = {'fullname': 'Mark Zuckerberg', 'Age': 30, 'job': 'Developer'},
will = {'fullname': 'Will Smith', 'Age': 45, 'job': 'Actor'}
file2.py
from file1 import *
name = raw_input('Please enter a name:')
global_vars = globals()
print(global_vars[name])
But still, since you could just use a nested dict I see no single valid reason to use globals() for this use case at all. Just declare your dicts under keys in another dict and you should be just fine.

Next to a nested dictionary you can also use an import alias to make you code cleaner.
import File1 as employees
name = raw_input("Enter name:")
print(getattr(employees, name)['Age'])

Related

update values in a list of dictionaries

I have the following list:
list_dict = [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': []}
]
I would like to add a hobby to R2:
for i in range(len(list_dict)):
people = list_dict[i]
if people['name'] == 'R2':
people['hobbies'] = ['lubrication']
print(list_dict)
I got what I was expecting but as a newbie I'd like to learn a few easy tricks to make it shorter.
I'd express as:
people = {person['name']: person for person in list_dict}
people['R2']['hobbies'] += ['lubrication'] # reads nicely as "add a hobby to R2"
For all those hung up on the academic concern of "potential people with same name", although the "Leetcode answer" would be:
for person in list_dict:
if person['name'] == 'R2':
person['hobbies'] += ['lubrication']
But in practice, remodeling data to have & use primary keys is probably what you want in most cases.
You can just iterate over the list and condense the if statement:
for person in list_dict:
person['hobbies'] = ['lubrication'] if person['name'] == 'R2' else person['hobbies']
There are some other answers here but in my eyes they don't really help a newbie seeking to shorten his code. I don't suggest to use the below proposed shortening except the looping over items in list instead of using indices, but to give here an answer with some maybe worth to know 'tricks' (you can have more than one name pointing to same variable/object, you can iterate directly over items of a list instead using indices) to a newbie here a shortened version of the code:
for p in l:
if p[n]=='R2': p[h]=['lubrication']
print(l)
and below all of the code using the proposed shortening with comments pointing out the 'tricks':
list_dict = [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': []},
{'name': 'R2', 'age': 15, 'country': 'Alduin', 'hobbies': []}
]
l = list_dict; n='name'; h='hobbies'
# I would like to add a hobby to R2:
"""
for i in range(len(list_dict)):
people = list_dict[i]
if people['name'] == 'R2':
people['hobbies'] = ['lubrication']
"""
# I got what I was expecting but as a newbie I'd like to learn a few
# easy tricks to make it shorter:
for p in l: # loop over items in list instead of using indices
if p[n]=='R2': p[h]=['lubrication'] # use short variable names
# ^-- give --^ long string constants short names
print(l)
there is no need to loop over the lenght, you can loop through the list and you can condense with a one-liner if statement
#!usr/bin/python3
from pprint import pprint
for person in list_dict:
person['hobbies'].append('lubrification') if person['name'] == 'R2' else ...
pprint(list_dict)
>>> [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': ["lubrification"]}
]
you can also do this with a comprehension:
[person['hobbies'].append('lubrification') for person in list_dict if person['name']]
But, if you just want to change one, you can use this code:
m = next(i for i,person in enumerate(list_dict) if person["name"]=="R2")
list_dict[m]["hobbies"].append("lubrification")

Return can close Loop for? (python/django)

Does return on python close the Loop for?
I'm asking that because I wrote a code that will search for me someone in a list and if know that person it will return me his age if not it will tell me "Person not found".
If the person is in the first place of the Array if find it but if it is in the second he doesn't why?
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
else:
return {'name': 'Person not found', 'age': 0}
def fname(request, name):
result = lerDoBanco(name)
if result['age'] > 0:
return HttpResponse('The person was found, has ' + str(result['age']) + ' years old')
else:
return HttpResponse('Person not found')
I ask that because if I comment the else statement it shows me all the people in the Array correctly.
When you call return operator it will terminate the current function execution and return value. So if you will use return inside your loop, return will terminate the loop and the function and return some value.
return terminates execution further and returns some desired value (default is None). Change indentation to make your code working :
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
return {'name': 'Person not found', 'age': 0}
It will iterate all the values to find the person then if not found then the default value {'name': 'Person not found', 'age': 0} will be returned.
From the moment you return you move out of the function, so out of the for loop as well.
What you thus can do is simply return the 'Person not found' at the end of the function:
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
return {'name': 'Person not found', 'age': 0}
Note that if the data is stored in the database, it is better to make a queryset to filter at the database side. Databases are optimized to search effectively. You can also specify db_index=True on a column such that the database builds an index allowing much faster retrieval.
A loop ends when one of the following happens:
loop condition evaluates to false
break is used
an exception is raised
a return statement is executed
The points above are the same for every programming language

How print each smaller dictionary in new line in nested dictionary

I wrote a nested dictionary program. The dictionary generates well but I would like every smaller dictionary to be printed in a new line.
import random
list_of_surname = ["Gates", "Bezos", "Buffett", "Zuckerberg", "Arnault",
"Page", "Sołowow", "Solorz"]
list_of_name = ["Bill", "Jeff", "Warren ", "Mark ", "Bernard", "Larry ",
"Michał", "Zygmunt"]
list_of_age = [73, 24, 35, 76, 64, 75, 86, 45]
list_of_profession = ["businessman", "chairman", "inventor", "pioneer",
"speculator", "programmer"]
def generator_of_random_nested_dictionary(number_of_dictionaries):
nested_dictionary = {f'person_{number_of_dictionaries}' :
{"surname":random.choice(list_of_surname),
"name":random.choice(list_of_name),
"age":random.choice(list_of_age),
"profession":random.choice(list_of_profession)}
for number_of_dictionaries in range (1,number_of_dictionaries+1)}
print("")
print ([(x,y)for x,y in nested_dictionary.items()],sep="\n")
print("")
'''
print((for key,values in nested_dictionary,sep="\n"))
'''
generator_of_random_nested_dictionary(3)
this is my output:
[('person_1', {'surname': 'Arnault', 'name': 'Larry ', 'age': 24, 'profession': 'inventor'}), ('person_2', {'surname': 'Arnault', 'name': 'Larry ', 'age': 35, 'profession': 'businessman'}), ('person_3', {'surname': 'Solorz', 'name': 'Michał', 'age': 76, 'profession': 'pioneer'})]
output is good but how to modify the print function so that each smaller dictionary is displayed in a new line? I would like to have output in this form:
[('person_1', {'surname': 'Arnault', 'name': 'Larry ', 'age': 24, 'profession': 'inventor'}),
('person_2', {'surname': 'Arnault', 'name': 'Larry ', 'age': 35, 'profession': 'businessman'}),
('person_3', {'surname': 'Solorz', 'name': 'Michał', 'age': 76, 'profession': 'pioneer'})]
Passing a list to print isn't doing what you want:
print ([(x,y)for x,y in nested_dictionary.items()],sep="\n")
To use the sep argument to print, you need to pass the elements of this list as separate arguments, which we can do with the * operator:
print (*[(x,y)for x,y in nested_dictionary.items()],sep="\n")
importing the pprint module and changing the line to this:
pprint.pprint([(x,y)for x,y in nested_dictionary.items()], width=100)
Did the work for me.

User input as query for nested dictionary

I have a nested dictionary and instead of a hard coded query to query for ownername John I want to prompt the user for a name and just to test it, I type John upon being prompted and the program crashes with an error that says string indices must be integers.
The below works fine and returns Kitty.
John = { 1: {'name': 'Kitty', 'kind': 'cat'},
2: {'name': 'Ruffle', 'kind': 'dog'},
3: {'name': 'Bobby', 'kind': 'fish'}
}
petownername = John[1]['name']
print(petownername)
This also works fine when I hardcode the owner_name to John and I input the dictionary query with f string.
John = { 1: {'name': 'Kitty', 'kind': 'cat'},
2: {'name': 'Ruffle', 'kind': 'dog'},
3: {'name': 'Bobby', 'kind': 'fish'}
}
owner_name = John
petname = f"{owner_name[1]['name']}"
print(petname)
But as mentioned above when I add new user input it stops working
John = { 1: {'name': 'Kitty', 'kind': 'cat'},
2: {'name': 'Ruffle','kind': 'dog'},
3: {'name': 'Bobby',' kind': 'fish'}
}
owner_name = str(input("Which pet owner do you want to look up?: "))
petname = f"{owner_name[1]['name']}"
print(petname)
I am getting this error:
Which pet owner do you want to look up?: John
Traceback (most recent call last):
File "test3.py", line 9, in <module>
petname = f"{owner_name[1]['name']}"
TypeError: string indices must be integers
So it works fine when I hardcode it and insert it via f string and input is clearly a string. Any idea why it's not working on user prompt?
Do I need to store and refer back to the user prompt in another way perhaps?
It's not working because in the second snippet, owner_name is a dict, while in the third snippet it's a string -- specifically owner_name = 'John' so owner_name[1] == 'o', and 'o'['name'] raises that TypeError. The f-string is irrelevant.
To fix it, use one more level of nested dicts. See How do I create a variable number of variables?.
By the way, instead of a dict with ints as keys, you might want to use a list instead.
pet_owners = {
"John": [
{'name': 'Kitty', 'kind': 'cat'},
{'name': 'Ruffle', 'kind': 'dog'},
{'name': 'Bobby',' kind': 'fish'},
]
}
owner_name = input('Pet owner name: ')
petname = pet_owners[owner_name][0]['name'] # Note the 0 instead of 1
print(petname)
Test run:
Pet owner name: John
Kitty
Also by the way, str(input()) is redundant in Python 3 since input() returns a string.

Replacing a specific item of a dict in a list of dicts? [duplicate]

This question already has answers here:
Find the index of a dict within a list, by matching the dict's value
(12 answers)
Closed 3 years ago.
Say I have the following list of dicts:
dicts = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5},
... ]
I'd like to replace the age of a given person with a given value.
def replace_age(person, age):
dicts[?]['age'] = age
replace_age("Tom", 45)
Assuming that name is unique, what's the most elegant way to go about this?
In a golden world: dicts[name=person]['age'] = age
Not a duplicate of Find the index of a dict within a list, by matching the dict's value: I'm looking to change the value, not get the index. And Tom is a pretty common name.
this is a variant:
def replace_age(person, age):
try:
dct = next(item for item in dicts if item["name"] == person)
except StopIteration:
# person not found
# here you could print a message or raise an error...
return
dct["age"] = age
this will only work if the names are unique. if they are not only the first occurrence will be replaced.
since the name is unique you can change your data structure where you keep your data to achieve your task efficiently:
efficient_dict = {e['name']: {'age' : e.get('age'), 'height': e.get('height')} for e in dicts}
def replace_age(person, age):
if person in efficient_dict:
efficient_dict[person]['age'] = age
Here's my version
dictionaries = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5}
]
def change_dict_person_age(dictionaries, person, age):
for dictionary in dictionaries:
if dictionary['name'] == person:
dictionary['age'] = age
# Uncomment the following line if you want to stop at the 1st
# match. Leave it as is if you want to modify all occurrences.
#break
change_dict_person_age(dictionaries, "Tom", 40)
print(dictionaries)
#[{'name': 'Tom', 'age': 40, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]
I also wrote a more generic version for broader user:
dictionaries = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5}
]
def change_dict(dictionaries, key_to_check, value_to_match, key_to_change, value_to_change):
for dictionary in dictionaries:
if dictionary[key_to_check] == value_to_match:
dictionary[key_to_change] = value_to_change
# Uncomment the following line if you want to stop at the 1st
# match. Leave it as is if you want to modify all occurrences.
#break
change_dict(dictionaries, "name", "Tom", "age", 50)
print(dictionaries)
#[{'name': 'Tom', 'age': 50, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]

Categories