Background:
I am reading a python file (.py) that has a number of functions defined and using a regex to get the names of all the functions and store them in a list.
d_fncs = {}
list_fncs = []
with open('/home/path/somefile.py', 'r') as f:
for row in f:
search = re.search(r'def (.*)\(', row)
if search:
list_fncs.append(search.group(1))
The above works fine and as expected returns a list of of the function names as strings. I have another list which I plan to use as a counter.
counter = [str(i) for i in range(1,len(list_fncs)+1)]
Finally, I zip the two lists to get a dictionary where the 'keys' are numbers and the associated 'values' are function names
d_fncs = dict(zip(counter,list_fncs))
The problem:
The intent here is to ask user for an input which would be matched with the key of this dictionary (counter). Once the key is matched, the function associated with it is executed. Something like this happens later in the code:
def option_to_run(check, option_enter_by_user):
if check == 'True':
return (connection(d_fncs[option]))
def connection(fnc):
conn_name = Connect(some args..) #class imported
fnc(conn_name)
In this case, as the values from dict are string, I get the following error:
File "/home/path/filename.py", line 114, in connection
fnc(conn_name)
TypeError: 'str' object is not callable
However, if I manually make a dict and run it then I have no issues and functions work as expected:
d_fncs_expected = {'1': function1, '2': function2, ....}
Right now what I am getting is this:
d_fncs = {'1': 'function1', '2': 'function2', ....}
....what can I do to get the dictionary to work in a way so I can call these functions? I want the values not to be strings but a type:class
Replace
fnc(conn_name)
to
eval(fnc)(conn_name) # or eval(fnc(conn_name))
or
globals()[fnc](conn_name)
For example
def myfn(arg):
print(arg +" is printed")
d = {1: 'myfn'}
fun_name = d[1] # 'myfn'
>>>fun_name("something")
TypeError: 'str' object is not callable
>>>eval(fun_name)("something")
something is printed
>>>globals()[fun_name]("someting")
something is printed
Related
I have a string
str = "Name John"
I want to change it to a dictionary.
{"Name":"John"}
How do I achieve this?
I Have tried using comprehension but I get an error.
str = "Arjun 23344"
Name = {str.split()}
Error
Traceback (most recent call last):
File "/home/daphney/Python/AGame.py", line 2, in <module>
Name = {x.split()}
TypeError: unhashable type: 'list'
You can split:
my_dict = {str.split(" ")[0]:str.split(" ")[1]}
Note: If you have, say, Name John Smith and want the dict to be Name:Smith, then you can just change the [1] to [-1] to get the last indexed item.
You can create a dictionary using dict function by providing list of [key,value] lists (or (key,value) tuples):
my_str = "Arjun 23344"
Name = dict([my_str.split()])
print(Name) # output: {'Arjun': '23344'}
Name = dict([str.split()])
This would only work if your string always splits into exactly two words. This works because the split call returns a list of two elements, which is then stored inside a containing list, and passed to the dict constructor. The latter can work properly with a sequence (list or other) of pairs (lists or other).
This works in this particular case, but is not robust or portable.
As there are only two strings in your variable.
string = "Name Shivank"
k,v = string.split()
d = dict()
d[k] = v
print(d) #output: {'Name':'Shivank'}
you can provide a second parameter to the split function to limit the number of separations (to 1 in this case):
dict([string.split(" ",1)])
this is a dummy version of what a function returns. I would like to know how to extract
'the.email#addresi.want' and 'Nextstringiwant from:
{'blah': {'blah1': 'the.email#addresi.want', 'blah2': 'Nextstringiwant'}, 'blah3': {'-note-': 'blah4', 'blah5': 'blah6', 'blah7': 'blah#bleble.blah', 'blah8': 'blah9'}}
I honestly don't understand the purpose for {} brackets very well, or how to work with it. I cannot change the function that returns this. Please help me, i'm lost. My gut tells me that I should convert this into a normal list and just get the desired position within that list, but it returns this error.
My code:
brackets = function().split(sep=':')
brackets.to_list()
email=brackets[2]
string=brackets[3]
The error:
brackets = creds.split(sep=':')
AttributeError: 'dict' object has no attribute 'split'
Note:
This is exactly how the function returns the {} list, I only changed the values for simplicity sake.
I would really appreciate
As the error message indicates, split is an attribute/method for a string, not for a dictionary.
Your function returns a Python dictionary.
Given your function is called function, you can access the values like this:
result = function()
email_address = result["blah"]["blah1"] # this will be 'the.email#addresi.want'
next_string = result["blah"]["blah2"] # this will be 'Nextstringiwant'
You can get further information on Python dictionaries on this site:
https://realpython.com/python-dicts/
mydict = {
'blah': {'blah1': 'the.email#addresi.want',
'blah2': 'Nextstringiwant'},
'blah3': {'-note-': 'blah4',
'blah5': 'blah6',
'blah7':
'blah#bleble.blah',
'blah8': 'blah9'}
}
[k_ for k_ in mydict.get("blah", dict()).values()]
Output:
['the.email#addresi.want', 'Nextstringiwant']
{} mean json object in Python.
if that function return is string, you should use Json module of python to convert it to json object and access its properties. For example:
import json
obj = json.loads(str_above)
print (obj.blah.blah1)
print (obj.blah.blah2)
Summary of issue: I'm trying to create a nested Python dictionary, with keys defined by pre-defined variables and strings. And I'm populating the dictionary from regular expressions outputs. This mostly works. But I'm getting an error because the nested dictionary - not the main one - doesn't like having the key set to a string, it wants an integer. This is confusing me. So I'd like to ask you guys how I can get a nested python dictionary with string keys.
Below I'll walk you through the steps of what I've done. What is working, and what isn't. Starting from the top:
# Regular expressions module
import re
# Read text data from a file
file = open("dt.cc", "r")
dtcc = file.read()
# Create a list of stations from regular expression matches
stations = sorted(set(re.findall(r"\n(\w+)\s", dtcc)))
The result is good, and is as something like this:
stations = ['AAAA','BBBB','CCCC','DDDD']
# Initialize a new dictionary
rows = {}
# Loop over each station in the station list, and start populating
for station in stations:
rows[station] = re.findall("%s\s(.+)" %station, dtcc)
The result is good, and is something like this:
rows['AAAA'] = ['AAAA 0.1132 0.32 P',...]
However, when I try to create a sub-dictionary with a string key:
for station in stations:
rows[station] = re.findall("%s\s(.+)" %station, dtcc)
rows[station]["dt"] = re.findall("%s\s(\S+)" %station, dtcc)
I get the following error.
"TypeError: list indices must be integers, not str"
It doesn't seem to like that I'm specifying the second dictionary key as "dt". If I give it a number instead, it works just fine. But then my dictionary key name is a number, which isn't very descriptive.
Any thoughts on how to get this working?
The issue is that by doing
rows[station] = re.findall(...)
You are creating a dictionary with the station names as keys and the return value of re.findall method as values, which happen to be lists. So by calling them again by
rows[station]["dt"] = re.findall(...)
on the LHS row[station] is a list that is indexed by integers, which is what the TypeError is complaining about. You could do rows[station][0] for example, you would get the first match from the regex. You said you want a nested dictionary. You could do
rows[station] = dict()
rows[station]["dt"] = re.findall(...)
To make it a bit nicer, a data structure that you could use instead is a defaultdict from the collections module.
The defaultdict is a dictionary that accepts a default type as a type for its values. You enter the type constructor as its argument. For example dictlist = defaultdict(list) defines a dictionary that has as values lists! Then immediately doing dictlist[key].append(item1) is legal as the list is automatically created when setting the key.
In your case you could do
from collections import defaultdict
rows = defaultdict(dict)
for station in stations:
rows[station]["bulk"] = re.findall("%s\s(.+)" %station, dtcc)
rows[station]["dt"] = re.findall("%s\s(\S+)" %station, dtcc)
Where you have to assign the first regex result to a new key, "bulk" here but you can call it whatever you like. Hope this helps.
I am creating a loop in order to append continuously values from user input to a dictionary but i am getting this error:
AttributeError: 'dict' object has no attribute 'append'
This is my code so far:
for index, elem in enumerate(main_feeds):
print(index,":",elem)
temp_list = index,":",elem
li = {}
print_user_areas(li)
while True:
n = (input('\nGive number: '))
if n == "":
break
else:
if n.isdigit():
n=int(n)
print('\n')
print (main_feeds[n])
temp = main_feeds[n]
for item in user:
user['areas'].append[temp]
Any ideas?
Like the error message suggests, dictionaries in Python do not provide an append operation.
You can instead just assign new values to their respective keys in a dictionary.
mydict = {}
mydict['item'] = input_value
If you're wanting to append values as they're entered you could instead use a list.
mylist = []
mylist.append(input_value)
Your line user['areas'].append[temp] looks like it is attempting to access a dictionary at the value of key 'areas', if you instead use a list you should be able to perform an append operation.
Using a list instead:
user['areas'] = []
On that note, you might want to check out the possibility of using a defaultdict(list) for your problem. See here
As the error suggests, append is not a method or attribute, meaning you cannot call append in the dictionary user.
Instead of
user['areas'].append[temp]
Use
user['areas'].update[temp]
Either
use dict.setdefault() if the key is not added yet to dictionary :
dict.setdefault(key,[]).append(value)
or use, if you already have the keys set up:
dict[key].append(value)
source: stackoverflow answers
I am trying to return two dictionaries. person_to_friends and person_to_networks are given functions, and profiles_file is a text file.
What I wrote is:
def load_profiles(profiles_file, person_to_friends, person_to_networks):
"""
(file, dict of {str : list of strs}, dict of {str : list of strs}) -> NoneType
Update person to friends and person to networks dictionaries to include
the data in open file.
"""
profiles_file = open('data.txt', 'r')
person_to_friends = person_to_friends(profiles_file)
person_to_networks = person_to_networks(profiles_file)
return person_to_friends, person_to_networks
This only gives me person_to_friends dictionary..Could anyone can help this problem?
What I want to return is
{person_to_friends}
{person_to_networks}
Simply do:
return (person_to_friends, person_to_networks)
and when you call the function you need to unpack the return value:
person_to_friends, person_to_networks = load_profiles(var1, var2, var3)
You can return only one value (this value can be a tuple, as in your case). However, you can yield as much values as you need:
def load_profiles(profiles_file, person_to_friends, person_to_networks):
"""
(file, dict of {str : list of strs}, dict of {str : list of strs}) -> NoneType
Update person to friends and person to networks dictionaries to include
the data in open file.
"""
profiles_file = open('data.txt', 'r')
person_to_friends = person_to_friends(profiles_file)
person_to_networks = person_to_networks(profiles_file)
yield person_to_friends # you can do it without temp variable, obv.
yield person_to_networks
The difference is that with yield statement you don't construct a temporary tuple just to return two results at once. However, getting the values out of your "function" (that became a generator) will be slightly more difficult:
profiles = load_profiles(your args)
will not actually run your function at all, it just initializes a generator. To actually get values, you'll need to:
person_to_friends = next(profiles)
person_to_networks = next(profiles)
or just do a loop:
for result in load_profiles(your args):
do_something_with_your_dictionaries
So your function will return one value: the initialized generator object. Iterating over it in a loop (it can be for loop, map, filter, list(your_generator) or something else) or just calling next(your_generator) will give you both dictionaries you actually need.
The way you are returning two dictionaries is fine, something funny must be going on in the other parts of the code, if your remove them, everything works fine:
def load_profiles():
person_to_friends = {'a' : 1}
person_to_networks = {'b' : 2}
return person_to_friends, person_to_networks
Result:
>>> load_profiles()
({'a': 1}, {'b': 2})
>>> dict_1, dict_2 = load_profiles()
>>> dict_1
{'a': 1}
>>> dict_2
{'b': 2}
Your docstring states that the function parameter person_to_friends is a
dict of {str : list of strs}
But then you call it as though it were a function and overwrite it with the result:
person_to_friends = person_to_friends(profiles_file)
Is this a mistake in the docstring, or the code?
Possibly you are masking the real function definition by having a locally defined variable of the same name (ie the parameter). In general it is bad practice to override a variable of one type (eg function) with another vastly different type (eg dict) - although there are exceptions to this.
maybe you can try
class temp(a, b):
return dict(a=a, b=b)