importing one function to another - python

I am importing the fun.py module into the chr_cnt function. The cnt_list function takes a list as argument. When I call this function in chr_cnt function using import, I am not sure how to pass an argument for the chr_cnt function to the cnt_list function.
My fun.py module:
def cnt_list(li):
my_dict = {}
for i in li:
if i in my_dict:
my_dict[i] = my_dict[i]+1
else:
my_dict[i] = 1
return my_dict
# print cnt_list([1,2,3,3,1])
My script:
import fun
def chr_cnt(s):
res={}
res=fun.cnt_list(s) # or res=fun.cnt_list(list(s))
return res
print chr_cnt("aabbc")
expected result:
{'a':2, 'b':2,'c':1}

This works fine for me? Are you sure you have the right indenting? I've made it a bit shorter for you:
fun.py:
def cnt_list(li):
my_dict = {}
for i in li:
if i in my_dict:
my_dict[i] = my_dict[i]+1
else:
my_dict[i] = 1
return my_dict
main.py:
import fun
def chr_cnt(s):
return fun.cnt_list(s)
print chr_cnt("aabbc")

Related

How can I use an updated dictionary from main() function in another function?

I have a dictionary that is in the main function and I want to use it in another function to present the data in a tabular format.
I had created the dictionary in a function as follows:
def file_reader():
config_dict = {}
newDict = {}
configParser = configparser.ConfigParser()
configParser.read('config.ini')
for section in configParser.sections():
for k,v in configParser.items(section):
config_dict[k] = v
config_dict = dict(configParser.items('SectionTwo'))
rev_dict = dict(map(reversed, configParser.items('SectionOne')))
for v in rev_dict:
newDict[k] = rev_dict[v]
list_vals = list(config_dict.values())
list_keys = list(config_dict.keys())
return rev_dict, newDict
I then used the dictionary created in the above function in main function as follows:
def main():
rev_dict, newDict = file_reader()
parser = ap.ArgumentParser()
parser.add_argument('-s', '--start', help='start script', action='store_true')
args = parser.parse_args()
elif args.start:
for k,v in rev_dict.items():
print("\nTestcase:" + v + "\n");print(v, "=", k);print("\n");time.sleep(5);
proc = sp.call([k], shell=True);time.sleep(5);
print('Process ID is:', os.getpid())
if proc != 0:
if proc < 0:
print("\nKilled by signal!\n", -proc)
else:
print("\nFailed with return code: ", proc)
newDict[v] = 'Fail'
print(json.dumps(dic, indent=4, sort_keys=True))
else:
print("\nOK\n")
newDict[v] = 'Pass';
print(json.dumps(dic, indent=4, sort_keys=True))
sipResponse(args.ip)
I had then created a function called read_file() where I want to generate a report and use the updated dictionary named newDict from main function.
def read_file():
rev_dict = file_reader()
shutil.copy("logfile.log", "file.txt")
f = open("file.txt", "r+")
headers = ['Testcase', 'Path']
data = sorted([(k,v) for k,v in rev_dict.items()])
f.write(tabulate(data, headers=headers, tablefmt="grid"))
f.close()
sys.exit(0)
Can someone please guide?
You need to introduce an argument to the read_file function:
def read_file(new_dict):
Then in main when you want to call the new function, call read_file(newDict). Notice how the argument name in the function is new_dict, thus showing that the two names are actually different.
Thus main might look something like this, with other code removed for simplicity: just add a call to the other method.
def main():
rev_dict, newDict = file_reader()
read_file(newDict)

xmltodict returns string instead of OrderedDict [duplicate]

The following Code produces an error, if there is only one "car" in "garage":
import xmltodict
mydict = xmltodict.parse(xmlstringResults)
for carsInGarage in mydict['garage']['car']:
# do something...
The Reason is that mydict['garage']['car'] is only a list if there is more than one element of "car". So I did something like this:
import xmltodict
mydict = xmltodict.parse(xmlstringResults)
if isinstance(mydict['garage']['car'], list):
for carsInGarage in mydict['garage']['car']:
# do something for each car...
else:
# do something for the car
to get the code to run. But for more advanced operations this is no solution.
Does someone know some kind of function to use, even if there is only one element?
This problem is discussed in this issue on Github. The xmltodict package now supports
d = xmltodict.parse(s, force_list={'car'})
Although this still doesn't create an empty list if the field is absent.
This is of course not an elegant way, but this is what i have done to get the code run (if someone hase the same probleme an found this via google):
import xmltodict
def guaranteed_list(x):
if not x:
return []
elif isinstance(x, list):
return x
else:
return [x]
mydict = xmltodict.parse(xmlstringResults)
for carsInGarage in guaranteed_list(mydict['garage']['car']):
# do something...
but i thing i will write my code again and "use XML directly" as one of the comments said.
I am using the combination of
1)
json_dict = xmltodict.parse(s, force_list={'item'})
And
2)
# Removes a level in python dict if it has only one specific key
#
# Examples:
# recursive_skip_dict_key_level({"c": {"a": "b"}}, "c") # -> {"a", "b"}
# recursive_skip_dict_key_level({"c": ["a", "b"]}, "c") # -> ["a", "b"]
#
def recursive_skip_dict_key_level(d, skipped_key):
if issubclass(type(d), dict):
if list(d.keys()) == [skipped_key]:
return recursive_skip_dict_key_level(d[skipped_key], skipped_key)
else:
for key in d.keys():
d[key] = recursive_skip_dict_key_level(d[key], skipped_key)
return d
elif issubclass(type(d), list):
new_list = []
for e in d:
new_list.append(recursive_skip_dict_key_level(e, skipped_key))
return new_list
else:
return d
# Removes None values from a dict
#
# Examples:
# recursive_remove_none({"a": None}) # -> {}
# recursive_remove_none([None]) # -> []
#
def recursive_remove_none(d):
if issubclass(type(d), dict):
new_dict = {}
for key in d.keys():
if not (d[key] is None):
new_dict[key] = recursive_remove_none(d[key])
return new_dict
elif issubclass(type(d), list):
new_list = []
for e in d:
if not (e is None):
new_list.append(recursive_remove_none(e))
return new_list
else:
return d
json_dict = recursive_skip_dict_key_level(json_dict, "item")
json_dict = recursive_remove_none(json_dict)
to interpret any "item" XML-elements as lists.
In addition to the existing answers, xmltodict now also supports the following to force everything to be a list:
xml = xmltodict.parse(s, force_list=True)

Nested dictionary that acts as defaultdict when setting items but not when getting items

I want to implement a dict-like data structure that has the following properties:
from collections import UserDict
class TestDict(UserDict):
pass
test_dict = TestDict()
# Create empty dictionaries at 'level_1' and 'level_2' and insert 'Hello' at the 'level_3' key.
test_dict['level_1']['level_2']['level_3'] = 'Hello'
>>> test_dict
{
'level_1': {
'level_2': {
'level_3': 'Hello'
}
}
}
# However, this should not return an empty dictionary but raise a KeyError.
>>> test_dict['unknown_key']
KeyError: 'unknown_key'
The problem, to my knowledge, is that python does not know whether __getitem__ is being called in the context of setting an item, i.e. the first example, or in the context of getting and item, the second example.
I have already seen Python `defaultdict`: Use default when setting, but not when getting, but I do not think that this question is a duplicate, or that it answers my question.
Please let me know if you have any ideas.
Thanks in advance.
EDIT:
It is possible to achieve something similar using:
def set_nested_item(dict_in: Union[dict, TestDict], value, keys):
for i, key in enumerate(keys):
is_last = i == (len(keys) - 1)
if is_last:
dict_in[key] = value
else:
if key not in dict_in:
dict_in[key] = {}
else:
if not isinstance(dict_in[key], (dict, TestDict)):
dict_in[key] = {}
dict_in[key] = set_nested_item(dict_in[key], value, keys[(i + 1):])
return dict_in
class TestDict(UserDict):
def __init__(self):
super().__init__()
def __setitem__(self, key, value):
if isinstance(key, list):
self.update(set_nested_item(self, value, key))
else:
super().__setitem__(key, value)
test_dict[['level_1', 'level_2', 'level_3']] = 'Hello'
>>> test_dict
{
'level_1': {
'level_2': {
'level_3': 'Hello'
}
}
}
It's impossible.
test_dict['level_1']['level_2']['level_3'] = 'Hello'
is semantically equivalent to:
temp1 = test_dict['level_1'] # Should this line fail?
temp1['level_2']['level_3'] = 'Hello'
But... if determined to implement it anyway, you could inspect the Python stack to grab/parse the calling line of code, and then vary the behaviour depending on whether the calling line of code contains an assignment! Unfortunately, sometimes the calling code isn't available in the stack trace (e.g. when called interactively), in which case you need to work with Python bytecode.
import dis
import inspect
from collections import UserDict
def get_opcodes(code_object, lineno):
"""Utility function to extract Python VM opcodes for line of code"""
line_ops = []
instructions = dis.get_instructions(code_object).__iter__()
for instruction in instructions:
if instruction.starts_line == lineno:
# found start of our line
line_ops.append(instruction.opcode)
break
for instruction in instructions:
if not instruction.starts_line:
line_ops.append(instruction.opcode)
else:
# start of next line
break
return line_ops
class TestDict(UserDict):
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
# inspect the stack to get calling line of code
frame = inspect.stack()[1].frame
opcodes = get_opcodes(frame.f_code, frame.f_lineno)
# STORE_SUBSCR is Python opcode for TOS1[TOS] = TOS2
if dis.opmap['STORE_SUBSCR'] in opcodes:
# calling line of code contains a dict/array assignment
default = TestDict()
super().__setitem__(key, default)
return default
else:
raise
test_dict = TestDict()
test_dict['level_1']['level_2']['level_3'] = 'Hello'
print(test_dict)
# {'level_1': {'level_2': {'level_3': 'Hello'}}}
test_dict['unknown_key']
# KeyError: 'unknown_key'
The above is just a partial solution. It can still be fooled if there are other dictionary/array assignments on the same line, e.g. other['key'] = test_dict['unknown_key']. A more complete solution would need to actually parse the line of code to figure out where the variable occurs in the assignment.

Global variable producing nothing in python

I have a program that has a global dictionary, "d", and I can print it out fine in a function but when I add or remove a value from it nothing happens.
d = {}
def main():
global d
# ADD SCORES
leadFile = open("leaderboard.txt","r")
leads = []
lead = leadFile.readline()
while lead != "":
leads.append(lead)
lead = leadFile.readline()
leadFile.close()
for lead in leads:
fields = lead.split(",")
d[fields[0]] = fields[1]
print(d)
main()
This works:
leaderboard.txt:
a,10
b,20
c,30
d,40
e,50
running your code:
$ python test.py
{'a': '10\n', 'b': '20\n', 'c': '30\n', 'd': '40\n', 'e': '50\n'}
test.py contains a copy/paste of your posted code. There are definitely some areas for improvement in the code, but this was taken as posted.
For what it's worth, you could simplify the code like this:
d = {}
def main():
global d
d.update(dict(item.split(',') for item in open('leaderboard.txt', 'r')))
print(d)
main()
If you don't have a very specific need to use the global variable, it's usually considered cleaner to pass objects as function parameters:
d = {}
def main(my_dict):
my_dict.update(dict(item.split(',') for item in open('leaderboard.txt', 'r')))
print(my_dict)
main(d)
I'd like to present an alternative to the "simplified" code in the other answer.
d = {}
def main():
with open("leaderboard.txt", "r") as leader_file:
d.update(dict(line.strip().split(',') for line in leader_file))
print(d)
main()
print(d)
As you can see you don't need global. As a bonus this code strips the line ends from the data.
Nevertheless I wouldn't use a global variable here but use a parameter if you want to use an existing dictionary.
d = {}
def main(data):
with open("leaderboard.txt", "r") as leader_file:
data.update(dict(line.strip().split(',') for line in leader_file))
main(d)

How to load into Globals in Python from a function

I have a function which load data into a dictionnary.
But, How can I load the dictionnary into Globals() inside a function.
Inside a function is important since we can do it easily outside on a script side.
def load237(filename):
filename = osp.abspath(filename)
old_cwd = os.getcwdu()
os.chdir(osp.dirname(filename))
error_message = None
try:
tar = tarfile.open(filename, "r")
tar.extractall()
pickle_filename = osp.splitext(filename)[0]+'.pickle'
data = cPickle.load(file(pickle_filename))
saved_arrays = {}
if load_array is not None:
try:
saved_arrays = data.pop('__saved_arrays__')
for (name, index), fname in saved_arrays.iteritems():
arr = np.load( osp.join(osp.dirname(filename), fname) )
if index is None:
data[name] = arr
elif isinstance(data[name], dict):
data[name][index] = arr
else:
data[name].insert(index, arr)
except KeyError:
pass
for fname in [pickle_filename]+[fn for fn in saved_arrays.itervalues()]:
os.remove(fname)
except (EOFError, ValueError), error:
error_message = unicode(error)
os.chdir(old_cwd)
return data, error_message
This one does not work (globals is local to the module/function...)
def load_inmemory(fpath):
globals().update(load237(fpath)[0])
You should really be storing those names on an object stored in a global and not as global variables. But you asked how to do it and so here is how:
Using Getting corresponding module from function with a for loop and setattr as modules do not support dictionary operations and it is possible to write the function as:
import sys
def load_inmemory():
module = sys.modules[load_inmemory.__module__]
for k, v in load237(fpath)[0].items():
setattr(module, k, v)
load_inmemory()
print x
I tested the following:
import sys
def func():
module = sys.modules[func.__module__]
for k,v in {'x':4}.items():
setattr(module, k, v)
func()
print x
Prints 4. Tested in Python 2.7.3.

Categories