Django KeyError: 'parent' [duplicate] - django

New to python and what looks like simple doable piece of code yielding KeyError:
patt=list('jkasb')
dict={}
for i in patt:
dict[i]= 1 if dict[i] is None else dict[i]+1 # This line throws error
error: KeyError: 'j'

In your case, the KeyError is occurring because you are trying to access a key which is not in the dictionary. Initially, the dictionary is empty. So, none of the keys exist in it.
This may seem strange if you are coming from a C++ background as C++ maps give default values for keys that don't exist yet. You can get the same behavior in python by using collections.defaultdict. The modified code is given below. I took the liberty of converting the defaultdict to a regular dictionary at the end of the code:
from collections import defaultdict
patt='jkasb'
my_default_dict=defaultdict(int)
for i in patt:
my_default_dict[i]+=1
my_dict = dict(my_default_dict) # converting the defaultdict to a regular dictionary
You can also solve this problem in a number of other ways. I am showing some of them below:
By checking if the key exists in the dictionary:
patt='jkasb'
my_dict={}
for i in patt:
my_dict[i]= 1 if i not in my_dict else my_dict[i]+1 # checking if i exists in dict
Using dict.get() without default return values:
patt='jkasb'
my_dict={}
for i in patt:
my_dict[i]= 1 if my_dict.get(i) is None else my_dict[i]+1 # using dict.get
print(my_dict)
Using dict.get() with default return values:
patt='jkasb'
my_dict={}
for i in patt:
my_dict[i]= my_dict.get(i, 0)+1 # using dict.get with default return value 0
As your code is actually just counting the frequency of each character, you can also use collections.Counter and then convert it to a dictionary:
from collections import Counter
patt='jkasb'
character_counter = Counter(patt)
my_dict = dict(character_counter)
Also, as dict is a built-in data type and I used dict to convert the defaultdict and Counter to a normal dictionary, I changed the name of the dictionary from dict to my_dict.

While building the dict dict, dict[i] is trying to access a key which does not exist yet, in order to check if a key exists in a dictionary, use the in operator instead:
d[i] = 1 if i not in d else d[i] + 1
Alternatives (for what you're trying to accomplish):
Using dict.get:
d[i] = d.get(i, 0) + 1
Using collections.defaultdict:
from collections import defaultdict
d = defaultdict(int)
for i in 'jkasb':
d[i] += 1
Using collections.Counter:
from collections import Counter
d = Counter('jkasb')
Avoid using dict (built-in type) as a variable name. And just iterate over 'jkasb' without having to convert it to a list, strings are iterable too.

As your dict is initially empty, trying to access any value with dict[i] will throw a KeyError.
You should replace this with .get() which returns None if the key is not found:
for i in patt:
dict[i] = 1 if dict.get(i) is None else dict[i] + 1
Another alternative, as suggested by #snakecharmerb, is to check beforehand whether or not the key exists in your dict:
for i in patt:
dict[i] = 1 if i not in dict else dict[i] + 1
Both solutions are equivalent, but the second is maybe more "idiomatic".

These snippets: dict[i] anddict[i]+1 will try to get a value from the dictionary with the corresponding key i. Since you have nothing in your dictionary, you get a KeyError.

you are trying to access a key in an empty dictionary, you can also use defaultdic so you do not care if the key exists already or not:
from collections import defaultdict
patt=list('jkasb')
my_dict = defaultdict(int)
for i in patt:
my_dict[i] += 1

Related

How to get 3 unique values using random.randint() in python?

I am trying to populate a list in Python3 with 3 random items being read from a file using REGEX, however i keep getting duplicate items in the list.
Here is an example.
import re
import random as rn
data = '/root/Desktop/Selenium[FILTERED].log'
with open(data, 'r') as inFile:
index = inFile.read()
URLS = re.findall(r'https://www\.\w{1,10}\.com/view\?i=\w{1,20}', index)
list_0 = []
for i in range(3):
list_0.append(URLS[rn.randint(1, 30)])
inFile.close()
for i in range(len(list_0)):
print(list_0[i])
What would be the cleanest way to prevent duplicate items being appended to the list?
(EDIT)
This is the code that i think has done the job quite well.
def random_sample(data):
r_e = ['https://www\.\w{1,10}\.com/view\?i=\w{1,20}', '..']
with open(data, 'r') as inFile:
urls = re.findall(r'%s' % r_e[0], inFile.read())
x = list(set(urls))
inFile.close()
return x
data = '/root/Desktop/[TEMP].log'
sample = random_sample(data)
for i in range(3):
print(sample[i])
Unordered collection with no duplicate entries.
Use the builtin random.sample.
random.sample(population, k)
Return a k length list of unique elements chosen from the population sequence or set.
Used for random sampling without replacement.
Addendum
After seeing your edit, it looks like you've made things much harder than they have to be. I've wired a list of URLS in the following, but the source doesn't matter. Selecting the (guaranteed unique) subset is essentially a one-liner with random.sample:
import random
# the following two lines are easily replaced
URLS = ['url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7', 'url8']
SUBSET_SIZE = 3
# the following one-liner yields the randomized subset as a list
urlList = [URLS[i] for i in random.sample(range(len(URLS)), SUBSET_SIZE)]
print(urlList) # produces, e.g., => ['url7', 'url3', 'url4']
Note that by using len(URLS) and SUBSET_SIZE, the one-liner that does the work is not hardwired to the size of the set nor the desired subset size.
Addendum 2
If the original list of inputs contains duplicate values, the following slight modification will fix things for you:
URLS = list(set(URLS)) # this converts to a set for uniqueness, then back for indexing
urlList = [URLS[i] for i in random.sample(range(len(URLS)), SUBSET_SIZE)]
Or even better, because it doesn't need two conversions:
URLS = set(URLS)
urlList = [u for u in random.sample(URLS, SUBSET_SIZE)]
seen = set(list_0)
randValue = URLS[rn.randint(1, 30)]
# [...]
if randValue not in seen:
seen.add(randValue)
list_0.append(randValue)
Now you just need to check list_0 size is equal to 3 to stop the loop.

How to print keys from a dictionary backwards

I have a dictionary in which I want to read each individual key backwards until it reaches the underscore. Once it reaches the underscore, it should stop so I can set its item equal to a new variable.
I understand that I can use str.partition() to seperate at a certain character and that I can use [::-1] to read a string backwards, but I am not sure how to use them together with a dictionary.
Payload_Values = {'Voltage_asleep(V)' : 10, 'Current_asleep(A)' : 5, 'Wattage_asleep' : 50}
for c in (Payload_Values.keys())
Payload_Values.partition(_)
You need to iterate a dict with keys() or items(), not iteritems(), in Python3 you need to convert these iterators to lists, otherwise it results an error if you add new element to the dict while iterating (I am just mentioning, this was ok in your example). Otherwise, you are close to the solution. I just do not understand completely, what do you want to do with the key? Print it? Take the part after the last underscore? Set a new key-value pair? Without knowing this, I am trying to present all combinations, please ask more specific if you need something else:
# this is because Python3 compatibility:
from __future__ import print_function
from future.utils import iteritems
for key, val in iteritems(Payload_Values):
# new key is the part after the last underscore
# or the whole string, if it does not contain underscore:
new_key = key.split('_')[-1]
# new key is the elements separated by `_`, reversed
# and rearranged to a string:
key_rev = '_'.join(key.split('_')[::-1])
# new key is the complete string reversed:
new_key = key[::-1]
#
# set a new element with the new key:
Payload_Values[new_key] = 'your new value'
# print the new key:
print(new_key)
# if you want to modify the dict in this loop:
for key, val in list(Payload_Values.items()):
# ...
Payload_Values[some_key] = some_value

Python, is there a easier way to add values to a default key?

The program I am working does the following:
Grabs stdout from a .perl program
Builds a nested dict from the output
I'm using the AutoVivification approach found here to build a default nested dictionary. I'm using this method of defaultdict because it's easier for me to follow as a new programmer.
I'd like to add one key value to a declared key per pass of the for line in the below code. Is there a easier way to add values to a key beyond making a [list] of values then adding said values as a group?
import pprint
class Vividict(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value
reg = 'NtUser'
od = Vividict()
od[reg]
def run_rip():
os.chdir('/Users/ME/PycharmProjects/RegRipper2.8') # Path to regripper dir
for k in ntDict:
run_command = "".join(["./rip.pl", " -r
/Users/ME/Desktop/Reg/NTUSER.DAT -p ", str(k)])
process = subprocess.Popen(run_command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = process.communicate() # wait for the process to terminate
parse(out)
# errcode = process.returncode // used in future for errorcode checking
ntDict.popitem(last=False)
def parse(data):
pattern = re.compile('lastwrite|(\d{2}:\d{2}:\d{2})|alert|trust|Value')
grouping = re.compile('(?P<first>.+?)(\n)(?P<second>.+?)
([\n]{2})(?P<rest>.+[\n])', re.MULTILINE | re.DOTALL)
if pattern.findall(data):
match = re.search(grouping, data)
global first
first = re.sub("\s\s+", " ", match.group('first'))
od[reg][first]
second = re.sub("\s\s+", " ", match.group('second'))
parse_sec(second)
def parse_sec(data):
pattern = re.compile(r'^(\(.*?\)) (.*)$')
date = re.compile(r'(.*?\s)(.*\d{2}:\d{2}:\d{2}.*)$')
try:
if pattern.match(data):
result = pattern.match(data)
hive = result.group(1)
od[reg][first]['Hive'] = hive
desc = result.group(2)
od[reg][first]['Description'] = desc
elif date.match(data):
result = date.match(data)
hive = result.group(1)
od[reg][first]['Hive'] = hive
time = result.group(2)
od[reg][first]['Timestamp'] = time
else:
od[reg][first]['Finding'] = data
except IndexError:
print('error w/pattern match')
run_rip()
pprint.pprint(od)
Sample Input:
bitbucket_user v.20091020
(NTUSER.DAT) TEST - Get user BitBucket values
Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket
LastWrite Time Sat Nov 28 03:06:35 2015 (UTC)
Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume
LastWrite Time = Sat Nov 28 16:00:16 2015 (UTC)
If I understand your question correctly, you want to change the lines where you're actually adding values to your dictionary (e.g. the od[reg][first]['Hive'] = hive line and the similar one for desc and time) to create a list for each reg and first value and then extend that list with each item being added. Your dictionary subclass takes care of creating the nested dictionaries for you, but it won't build a list at the end.
I think the best way to do this is to use the setdefault method on the inner dictionary:
od[reg][first].setdefault("Hive", []).append(hive)
The setdefault will add the second value (the "default", here an empty list) to the dictionary if the first argument doesn't exist as a key. It preempts the dictionary's __missing__ method creating the item, which is good, since we want a the value to be list rather than another layer of dictionary. The method returns the value for the key in all cases (whether it added a new value or if there was one already), so we can chain it with append to add our new hive value to the list.

Update a python dictionary with an arbitrarily long list of values

I have a work problem in which I needed to be able to update values in a dictionary from an arbitrarily long list of keys. Both the key list and the dictionary are generated from the same data at run time, but I don't know how many keys will be in the data before. The list of keys to take from the data is user specified at run time.
OK, so this works out to having to be able to update values in a dictionary from a list information consisting of:
1. a list of keys, ordered in the same order as the key nesting in the dictionary
2. a value to update per that key list information.
I think I've got a solution, by scavenging from this site: https://gist.github.com/hrldcpr/2012250 , and also the python autoviv(), which i liked better than that default tree object.
Here's my solution. Depending on what you feed the function, you should be able to generate a dictionary from list(s), and/or update a value at a specific place in the structure.
If you spot glaring errors or opportunities for improvement, I would appreciate your constructive feedback.
from pprint import *
from collections import defaultdict
from operator import getitem
class autoviv(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
def add(t,path,genorupdate='generate',val=0):
if genorupdate=='generate':
for node in path:
t = t[node]
elif genorupdate=='update':
for node in path:
if path.index(node)==len(path)-1:
t[node]=val
t = t[node]
d=autoviv()
# test lists to generate dictionary
l=['a','b','c']
l2=['a','b','d']
# TEST 1: generate dictionary with 2 kvps: c and d, nested under b:
add(d,l)
add(d,l2)
for k in d.keys():
print k, d[k]
# RESULT: a {'b': {'c': {}, 'd': {}}}
# TEST 2, update the value for the a,b,d key to 2 w/o disturbing anything else or
# generating additional structure
add(d,l2,'update',2)
for k in d.keys():
print k, d[k]
# RESULT: a {'b': {'c': {}, 'd': 2}}

Using integer as dictionary key using dict()

I'm trying to use numbers as my dict key. Is there anyway to initiate the dictionary using dict() method?
This works
mydict = { '100':'hundred', '200':'two hundred'}
This doesn't work?
mydict = dict( 100='hundred' )
The error says 'keyword can't be an expression' and I couldn't find any solution.
Thank you.
I can't understand your question exactly, but you mentioned to use number as dict key right? you just directly initiate it using integer instead string like this..
a = {1:'one',100:'hundered'}
print a
{1: 'one', 100: 'hundrered'}
No, it mist be a valid python identifier, so it cannot start with a number.
You can read where i found it at here in the part about dict
https://docs.python.org/2/library/stdtypes.html#typesmapping
Like the comment above says you can use an int, since dictionaries just hash the string and you get an int anyways, in the case of an int it just hashes to itself. But it doesnt work with dict ()
On that page it shows you can do
mydict = dict (zip ([1], ["one"]))
Which is kinda ugly imo, but seems to get the job done
To use the dict method you need to feed it a list or tuple of lists or tuples.
>>> dict([(100, 'hundred'), (200, 'two hundred')])
{200: 'two hundred', 100: 'hundred'}