NameError, name is not defined - python

I wrote a simple code to check if a list is sorted or not.
I have two questions:
First, my result is wrong. I guess the issue is with following the line. Which one is correct?:
sorted_list = mylist[:].sort()
sorted_list = list(mylist[:]).sort()
As second question, when I try to print(sorted_list), I get NameError which is sorted_list is not defined which is weird. Because I've already defined it in the second line. Would you please help me understand why I'm getting this error?
def is_sorted(mylist):
sorted_list = mylist[:].sort()
# mylist.sort()
if sorted_list == mylist:
return True
else:
return False
print(is_sorted(['Aajid', 'Bafiee', 'Hello']))
print(sorted_list)
Output:
False
Traceback (most recent call last):
File "e:\NectCloud\Python\is_sorted.py", line 11, in <module>
print(sorted_list)
^^^^^^^^^^^
NameError: name 'sorted_list' is not defined
Thanks

Use
mylist = [1, 5, 3, 6, 2]
sorted_list = sorted(mylist)
mylist.sort() does inplace sorting and returns None. For more information about sorting see https://docs.python.org/3/howto/sorting.html.
sorted_list is not defined in outer scope since it is only defined in the function scope. See https://realpython.com/python-scope-legb-rule/.

Related

Why is the updated[value] = [] giving me TypeError: unhashable type: 'list'? [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Why can't I use a list as a dict key in python?
(11 answers)
Closed 4 months ago.
I'm trying to take a file that looks like this:
AAA x 111
AAB x 111
AAA x 112
AAC x 123
...
And use a dictionary to so that the output looks like this
{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}
This is what I've tried
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline!= "":
list = []
list = readline.split(" ")
j = list.index("x")
k = list[0:j]
v = list[j + 1:]
d = {}
if k not in d == False:
d[k] = []
d[k].append(v)
readline = file.readline().rstrip()
I keep getting a TypeError: unhashable type: 'list'. I know that keys in a dictionary can't be lists but I'm trying to make my value into a list not the key. I'm wondering if I made a mistake somewhere.
As indicated by the other answers, the error is to due to k = list[0:j], where your key is converted to a list. One thing you could try is reworking your code to take advantage of the split function:
# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
d = {}
# Here we use readlines() to split the file into a list where each element is a line
for line in f.readlines():
# Now we split the file on `x`, since the part before the x will be
# the key and the part after the value
line = line.split('x')
# Take the line parts and strip out the spaces, assigning them to the variables
# Once you get a bit more comfortable, this works as well:
# key, value = [x.strip() for x in line]
key = line[0].strip()
value = line[1].strip()
# Now we check if the dictionary contains the key; if so, append the new value,
# and if not, make a new list that contains the current value
# (For future reference, this is a great place for a defaultdict :)
if key in d:
d[key].append(value)
else:
d[key] = [value]
print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
Note that if you are using Python 3.x, you'll have to make a minor adjustment to get it work properly. If you open the file with rb, you'll need to use line = line.split(b'x') (which makes sure you are splitting the byte with the proper type of string). You can also open the file using with open('filename.txt', 'rU') as f: (or even with open('filename.txt', 'r') as f:) and it should work fine.
Note:
This answer does not explicitly answer the asked question. the other answers do it. Since the question is specific to a scenario and the raised exception is general, This answer points to the general case.
Hash values are just integers which are used to compare dictionary keys during a dictionary lookup quickly.
Internally, hash() method calls __hash__() method of an object which are set by default for any object.
Converting a nested list to a set
>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
This happens because of the list inside a list which is a list which cannot be hashed. Which can be solved by converting the internal nested lists to a tuple,
>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])
Explicitly hashing a nested list
>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506
The solution to avoid this error is to restructure the list to have nested tuples instead of lists.
You're trying to use k (which is a list) as a key for d. Lists are mutable and can't be used as dict keys.
Also, you're never initializing the lists in the dictionary, because of this line:
if k not in d == False:
Which should be:
if k not in d == True:
Which should actually be:
if k not in d:
The reason you're getting the unhashable type: 'list' exception is because k = list[0:j] sets k to be a "slice" of the list, which is logically another, often shorter, list. What you need is to get just the first item in list, written like so k = list[0]. The same for v = list[j + 1:] which should just be v = list[2] for the third element of the list returned from the call to readline.split(" ").
I noticed several other likely problems with the code, of which I'll mention a few. A big one is you don't want to (re)initialize d with d = {} for each line read in the loop. Another is it's generally not a good idea to name variables the same as any of the built-ins types because it'll prevent you from being able to access one of them if you need it — and it's confusing to others who are used to the names designating one of these standard items. For that reason, you ought to rename your variable list variable something different to avoid issues like that.
Here's a working version of your with these changes in it, I also replaced the if statement expression you used to check to see if the key was already in the dictionary and now make use of a dictionary's setdefault() method to accomplish the same thing a little more succinctly.
d = {}
with open("nameerror.txt", "r") as file:
line = file.readline().rstrip()
while line:
lst = line.split() # Split into sequence like ['AAA', 'x', '111'].
k, _, v = lst[:3] # Get first and third items.
d.setdefault(k, []).append(v)
line = file.readline().rstrip()
print('d: {}'.format(d))
Output:
d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
The reason behind this is the list contains list of values. Like:
a = [[1,2],[1,2],[3,4]]
And this won't work with something like this:
list(set(a))
To fix this you can transform the interior list to tuple, like :
a = [(1,2),(1,2),(3,4)]
This will work !
The TypeError is happening because k is a list, since it is created using a slice from another list with the line k = list[0:j]. This should probably be something like k = ' '.join(list[0:j]), so you have a string instead.
In addition to this, your if statement is incorrect as noted by Jesse's answer, which should read if k not in d or if not k in d (I prefer the latter).
You are also clearing your dictionary on each iteration since you have d = {} inside of your for loop.
Note that you should also not be using list or file as variable names, since you will be masking builtins.
Here is how I would rewrite your code:
d = {}
with open("filename.txt", "r") as input_file:
for line in input_file:
fields = line.split()
j = fields.index("x")
k = " ".join(fields[:j])
d.setdefault(k, []).append(" ".join(fields[j+1:]))
The dict.setdefault() method above replaces the if k not in d logic from your code.
python 3.2
with open("d://test.txt") as f:
k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
d={}
for i,_,v in k:
d.setdefault(i,[]).append(v)

"Name of function is not defined"

A complete newbie's question:
The code is intended to find the longest string in a list and display it.
It does not work when I run it (as a file, or directly in the shell). I keep getting an error message that the function's name is not recognized. Your help and advice would be highly appreciated.
The correct result is shown with the print command, but when I try to run the complete file I keep getting the above-mentioned error.
def longest(mylist):
mylist = ["111", "44", "baking", "dot"]
list1 = max(["111", "44", "baking", "dot"], key=len)
longest(list1);
print(list1)
Error running the file:
File "<stdin>", line 1
python [filename].py
SyntaxError: invalid syntax
Error when pasting the code into the shell:
SyntaxError: invalid syntax
>>> mylist = ["111", "44", "baking", "dot"]
>>> list1 = max(["111", "44", "baking", "dot"], key=len)
>>> longest(list1);
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'longest' is not defined
>>> print(list1)
baking
The function does not do anything in your code.
Could have shorten to the below.
max_value = max(["111", "44", "baking", "dot"], key=len)
print(max_value)
Your code is not written properly, you should go through python tutorials to learn the basics. There are plenty of tutorials available on internet.
Python Tutorial at TutorialsPoint
Python Official Doc
Now, the answer to your question is :
#!/usr/bin/python
# This is the function which takes list as an argument and
# returns the longest string from the list
def longest(mylist) :
l = max(mylist, key=len)
return l
# This is the list which contains all the strings
mylist = ["111", "44", "baking", "dot"]
# This is the function call with "mylist" as argument
# and, the return value is assigned to a variable "x"
x = longest(mylist)
# prints the output
print(x)
This is not a solution to your problem where longest can't be found, but a working implementation of your code.
def longest(mylist):
return max(mylist, key=len)
list1 = ["111", "44", "baking", "dot"]
print(longest(list1))
Your problem is in your function.
You're receiving an argument in your function and you're overriding this argument at line 2.
Here what your function needs to look like
def longest(mylist):
mylist = max(mylist, key=len)
return mylist
And then after you're calling your function with your argument
mylist = ["111", "44", "baking", "dot"]
mylist = longest(mylist);
print(mylist)
Plus in your shell you didn't define your function so the interpreter doesn't know it

Recursion can't append list

Here I use a simplified code to demonstrate what I've encountered:
def recTry(inList):
print(inList)
if len(inList) < 10:
recTry(inList.append(1))
I hope with recursion it'll grow like [1], [1, 1], [1, 1, 1] ...
But actually run that will yield this:
>>> recTry([1])
[1]
None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in recTry
File "<stdin>", line 3, in recTry
TypeError: object of type 'NoneType' has no len()
inList become None since the second recursion.
So How can I code to make the inList appended with each recursion?
inList.append(1) returns None so you pass None while recursion
what you can do is:
def recTry(inList):
print(inList)
if len(inList) < 10:
inList.append(1)
recTry(inList)
else:
return inList
you try to call function with result of inList.append(1) but it is None
try to:
if len(inList) < 10:
inList.append(1)
recTry(inList)
It is a convention in Python that methods that mutate sequences return None. Thus the value your passing in first returns nothing which is your problem.
On the 4th line of your function,
recTry(inList.append(1))
inList.append(1) returns None after appending 1 to the existing list. This None is what you are passing to recTry method. You can try this instead to make the inList appended with each recursion:
inList.append(1)
recTry(inList)

Confusion in file functioning and append function using Python

I have two questions for an exam.
t2=("A","B","Hello")
alist=["Barney",["Wilma"]]
print(alist[1].append(t2))
answer:
None
I thought it would be [“Wilma”,(“A”,”B”,”Hello”)]
AND
file has:
James,8,9
Sonia,7,6
Clark,4,5
code:
endofprogram=False
try:
infile=open("names.txt",”r”)
except IOError:
print("Error reading file")
endofprogram=True
if endofprogram==False:
for line in infile:
line.strip('\n')
alist=line.split(',')
print(alist)
Answer
['James','8','9\n']
['Sonia','7','6\n']
['Clark','4','5\n']
Why is '\n' still there?
LASTLY:
def change(aList):
aList=aList.pop()
aList.append(5)
return
def main():
mylist=[1,2,[3]]
change(mylist)
print(mylist)
main()
Answer:
[1,2]
Why is this the answer? shouldn't it be [1,2,5]?
list.append is an in-place operation, it modifies the list in-place and returns None.
>>> lst = []
>>> repr(lst.append(1)) #returns None
'None'
>>> lst #list modified
[1]
Strings are immutable, you need to re-assign the result of .strip() call back to a variable.
line = line.strip('\n') #re-assign the new returned string to a variable.
alist = line.split(',')
You re-assigned aList to a different list, so the .append() call won't affect the originally passed list.
def change(aList):
aList = aList.pop() #Now aList points to [3] not to `[1, 2, [3]]`
aList.append(5)
You can simply use the assignment statement here:
aList[-1] = 5
list.append() is an operation which returns None because it modifies the list in place. You must print the actual list to get the output you expect.
line.strip("\n") does strip the newline, but it never gets saved anywhere. Strings are immutable in python, thus str.strip() returns a new string with the characters stripped. The correct way to use it is to say line = line.strip("\n").
Example 1:
>>> alist[1].append(t2)
>>> print alist
['Barney', ['Wilma', ('A', 'B', 'Hello')]]
Example 2:
>>> line = "Foo\n"
>>> line.strip("\n")
'Foo'
>>> line
'Foo\n'
>>> line = line.strip("\n")
>>> line
'Foo'
The append function returns nothing, thus the None result. It only appends to the list.
The strip function only removes characters at the end & beginning. If you are working on Windows, the actual line ending may well be \n\r, making the last character \r. That is not removed by your strip command.
Your third problem is because in the change function, the aList value is lost as soon the function Change exists. You should do:
def Change(l):
l.pop()
l.append(5)
In Python, an assignment does not change any underlying variable. Instead, the name is bound to a new value. Thus, after the line alIst = aList.pop(), aList points to [3], but is no longer linked the the myList object. After the append function, aList points to [3, 5], but this object is garbage collected as soon as Change returns.

How to overcome TypeError: unhashable type: 'list' [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Why can't I use a list as a dict key in python?
(11 answers)
Closed 4 months ago.
I'm trying to take a file that looks like this:
AAA x 111
AAB x 111
AAA x 112
AAC x 123
...
And use a dictionary to so that the output looks like this
{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}
This is what I've tried
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline!= "":
list = []
list = readline.split(" ")
j = list.index("x")
k = list[0:j]
v = list[j + 1:]
d = {}
if k not in d == False:
d[k] = []
d[k].append(v)
readline = file.readline().rstrip()
I keep getting a TypeError: unhashable type: 'list'. I know that keys in a dictionary can't be lists but I'm trying to make my value into a list not the key. I'm wondering if I made a mistake somewhere.
As indicated by the other answers, the error is to due to k = list[0:j], where your key is converted to a list. One thing you could try is reworking your code to take advantage of the split function:
# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
d = {}
# Here we use readlines() to split the file into a list where each element is a line
for line in f.readlines():
# Now we split the file on `x`, since the part before the x will be
# the key and the part after the value
line = line.split('x')
# Take the line parts and strip out the spaces, assigning them to the variables
# Once you get a bit more comfortable, this works as well:
# key, value = [x.strip() for x in line]
key = line[0].strip()
value = line[1].strip()
# Now we check if the dictionary contains the key; if so, append the new value,
# and if not, make a new list that contains the current value
# (For future reference, this is a great place for a defaultdict :)
if key in d:
d[key].append(value)
else:
d[key] = [value]
print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
Note that if you are using Python 3.x, you'll have to make a minor adjustment to get it work properly. If you open the file with rb, you'll need to use line = line.split(b'x') (which makes sure you are splitting the byte with the proper type of string). You can also open the file using with open('filename.txt', 'rU') as f: (or even with open('filename.txt', 'r') as f:) and it should work fine.
Note:
This answer does not explicitly answer the asked question. the other answers do it. Since the question is specific to a scenario and the raised exception is general, This answer points to the general case.
Hash values are just integers which are used to compare dictionary keys during a dictionary lookup quickly.
Internally, hash() method calls __hash__() method of an object which are set by default for any object.
Converting a nested list to a set
>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
This happens because of the list inside a list which is a list which cannot be hashed. Which can be solved by converting the internal nested lists to a tuple,
>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])
Explicitly hashing a nested list
>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506
The solution to avoid this error is to restructure the list to have nested tuples instead of lists.
You're trying to use k (which is a list) as a key for d. Lists are mutable and can't be used as dict keys.
Also, you're never initializing the lists in the dictionary, because of this line:
if k not in d == False:
Which should be:
if k not in d == True:
Which should actually be:
if k not in d:
The reason you're getting the unhashable type: 'list' exception is because k = list[0:j] sets k to be a "slice" of the list, which is logically another, often shorter, list. What you need is to get just the first item in list, written like so k = list[0]. The same for v = list[j + 1:] which should just be v = list[2] for the third element of the list returned from the call to readline.split(" ").
I noticed several other likely problems with the code, of which I'll mention a few. A big one is you don't want to (re)initialize d with d = {} for each line read in the loop. Another is it's generally not a good idea to name variables the same as any of the built-ins types because it'll prevent you from being able to access one of them if you need it — and it's confusing to others who are used to the names designating one of these standard items. For that reason, you ought to rename your variable list variable something different to avoid issues like that.
Here's a working version of your with these changes in it, I also replaced the if statement expression you used to check to see if the key was already in the dictionary and now make use of a dictionary's setdefault() method to accomplish the same thing a little more succinctly.
d = {}
with open("nameerror.txt", "r") as file:
line = file.readline().rstrip()
while line:
lst = line.split() # Split into sequence like ['AAA', 'x', '111'].
k, _, v = lst[:3] # Get first and third items.
d.setdefault(k, []).append(v)
line = file.readline().rstrip()
print('d: {}'.format(d))
Output:
d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
The reason behind this is the list contains list of values. Like:
a = [[1,2],[1,2],[3,4]]
And this won't work with something like this:
list(set(a))
To fix this you can transform the interior list to tuple, like :
a = [(1,2),(1,2),(3,4)]
This will work !
The TypeError is happening because k is a list, since it is created using a slice from another list with the line k = list[0:j]. This should probably be something like k = ' '.join(list[0:j]), so you have a string instead.
In addition to this, your if statement is incorrect as noted by Jesse's answer, which should read if k not in d or if not k in d (I prefer the latter).
You are also clearing your dictionary on each iteration since you have d = {} inside of your for loop.
Note that you should also not be using list or file as variable names, since you will be masking builtins.
Here is how I would rewrite your code:
d = {}
with open("filename.txt", "r") as input_file:
for line in input_file:
fields = line.split()
j = fields.index("x")
k = " ".join(fields[:j])
d.setdefault(k, []).append(" ".join(fields[j+1:]))
The dict.setdefault() method above replaces the if k not in d logic from your code.
python 3.2
with open("d://test.txt") as f:
k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
d={}
for i,_,v in k:
d.setdefault(i,[]).append(v)

Categories