2

This is what I am supposed to do in my assignment:

This function is used to create a bank dictionary. The given argument is the filename to load. Every line in the file will look like key: value Key is a user's name and value is an amount to update the user's bank account with. The value should be a number, however, it is possible that there is no value or that the value is an invalid number.

What you will do:

  • Try to make a dictionary from the contents of the file.
  • If the key doesn't exist, create a new key:value pair.
  • If the key does exist, increment its value with the amount.
  • You should also handle cases when the value is invalid. If so, ignore that line and don't update the dictionary.
  • Finally, return the dictionary.

Note: All of the users in the bank file are in the user account file.

Example of the contents of 'filename' file:

 Brandon: 115.5
 James: 128.87
 Sarah: 827.43
 Patrick:'18.9

This is my code:

bank = {}
with open(filename) as f:
    for line in f:
        line1 = line
        list1 = line1.split(": ")
        if (len(list1) == 2):
            key = list1[0]
            value = list1[1]
            is_valid = value.isnumeric()
            if is_valid == True
               value1 = float(value)
               bank[(key)] = value1

return bank

My code returns a NoneType object which causes an error but I don't know where the code is wrong. Also, there are many other errors. How can I improve/fix the code?

Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
coder_not_found
  • 202
  • 2
  • 13

3 Answers3

2

Try this code and let me explain everything on it because it depends on how much you're understanding Python Data structure:

Code Syntax

adict = {}
with open("text_data.txt") as data:
    """
        adict (dict): is a dictionary variable which stores the data from the iteration 
        process that's happening when we're separating the file syntax into 'keys' and 'values'. 
        We're doing that by iterate the file lines from the file and looping into them.
        The `line` is each line from the func `readlines()`. Now the magic happens here,
        you're playing with the line using slicing process which helps you to choose 
        the location of the character and play start from it. BUT, 
        you'll face a problem with how will you avoid the '\n' that appears at the end of each line. 
        you can use func `strip` to remove this character from the end of the file.
    """
    adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip('\n')  for line in data.readlines()}
    print(adict)

Output

{' Brandon': '115.5', ' James': '128.87', ' Sarah': '827.43', ' Patrick': "'18.9"}

In term of Value Validation by little of search you will find that you can check the value if its a number or not

According to Detect whether a Python string is a number or a letter

a = 5
def is_number(a):
    try:
        float (a)
    except ValueError:
        return False
    else: 
        return True

By Calling the function

print(is_number(a))
print(is_number(1.4))
print(is_number('hello'))

OUTPUT

True
True
False

Now, let's back to our code to edit;

All you need to do is to add condition to this dict..

adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip(' \n')  for line in data.readlines() if is_number(line[line.index(':')+1: ].strip('\n')) == True}

OUTPUT

{'Brandon': '115.5', 'James': '128.87', 'Sarah': '827.43'}

You can check the value of the dict by passing it to the function that we created

Code Syntax

print(is_number(adict['Brandon']))

OUTPUT

True

You can add more extensions to the is_number() function if you want.

Ahmed
  • 796
  • 1
  • 5
  • 16
1

You're likely hitting the return in the else statement, which doesn't return anything (hence None). So as soon as there is one line in your file that does not contain 2 white-space separated values, you're returning nothing.

Also note that your code is only trying to assign a value to a key in a dictionary. It is not adding a value to an existing key if it already exists, as per the documentation.

robbo
  • 525
  • 3
  • 11
  • thanks, and I am supposed to ignore the line in the file which doesn't have a value or has a invalid value. how do I ignore that line without using return. – coder_not_found Dec 20 '20 at 05:45
  • your if-statement only executes when the condition is met. If you don't include the else part then that is ignored automatically. So you basically would do nothing and hence go to the next iteration of your loop that gets the next line from your file. – robbo Dec 20 '20 at 05:46
  • I removed the else part but the program is still returning a NoneType. – coder_not_found Dec 20 '20 at 05:52
  • Can you include an example of the input file that you're trying to read? Does it only have 2 columns? – robbo Dec 20 '20 at 05:54
  • all the lines of the file are like this; key:value – coder_not_found Dec 20 '20 at 05:59
  • in that case can you write: `list1 = line1.split(": ")` instead of the line that you have? – robbo Dec 20 '20 at 06:00
  • as mentions above in assignment; some keys might not have values or the values are invalid – coder_not_found Dec 20 '20 at 06:00
  • thanks. I tried as you suggested. now I got a error; ''unsupported operand type(s) for -:'float' and 'str''' does this mean I have to return answer in floats? – coder_not_found Dec 20 '20 at 06:12
  • *when I run the program there is test cell which checks if the dictionary has everything in the file, will it be helpful if I add the test cell to the question? – coder_not_found Dec 20 '20 at 06:14
  • Yes re the float and string question. You are still a few steps away from the problem description, including converting strings to numbers, but potentially error handling if the string can't be converted. Also the summing of the existing value for a key with the new value if the key already exists will need some thought from your end to avoid a KeyError, etc... But I think you should search for some of these items yourself. – robbo Dec 20 '20 at 06:18
  • ok thanks for helping; here is a line from the test-cell - "tools.assert_false(len(bank) == 0)" when I run the program it seems to return False to the above line. which means my code has added 0 key:value pairs to the dictionary. – coder_not_found Dec 20 '20 at 06:30
  • I don't think it will be required to for sum the existing value, because as above in the code the dictionary bank{} starts with no key:value pairs. (the "bank{}" was default code) – coder_not_found Dec 20 '20 at 06:33
1

This should effectively do the job:

bank = {}
with open(filename) as file:
    for line in file:
        key, val = line.rsplit(": ", 1) # This will split on the last ': ' avoiding ambiguity of semi-colons in the middle
        # Using a trial and error method to convert number to float
        try:
            bank[key] = float(val)
        except ValueError as e:
            print(e)
return bank
Nishith Savla
  • 310
  • 2
  • 10