Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Python function returning none sometimes

Options
  • 14-01-2015 4:28pm
    #1
    Registered Users Posts: 416 ✭✭


    Hi

    I've got the following function which reads in a csv file and searches for the provided argument in row 1 and returns the value in row2.
    def generate_bic(sort_code):
    	for row in fooreader:
    		value = row[0]
    		if value == sort_code:
    			bic = row[1]
    			return bic
    

    The csv file is just a list of bank sort codes in row 1 with the corresponding BIC in row 2. So when the function is called with a sort code it returns the corresponding BIC as a string.
    Anybody any ideas on why it's returning none sometimes?


Comments

  • Registered Users Posts: 10,493 ✭✭✭✭28064212


    Are you sure there's a value there? Some sort codes don't have a corresponding BIC

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    Yup - if the sort code provided isn't in the file, the function will return None, which is the default return value from a Python function if you don't explicitly return something.


  • Hosted Moderators Posts: 3,331 ✭✭✭Splinter


    maybe try edit it to add an else?
    def generate_bic(sort_code):
    	for row in fooreader:
    		value = row[0]
    		if value == sort_code:
    			bic = row[1]
    			return bic
                    else:
                            ##do something else
    

    you could also use "try" and "except" instead which may do the same :)


  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    Mmm, that won't work - it will "do something else" if the first line of the file doesn't match.

    The "do something else" just has to follow the "for" loop - if that loop completes, the sort code wasn't in the file.


  • Registered Users Posts: 416 ✭✭gouche


    Thanks for the replies.

    There is definitely a corresponding BIC.
    The file only includes sort codes that are reachable by SEPA.
    I've also manually checked!

    So this is the full code. I've added a flag that will print True if the code thinks the sort code isn't in the file.
    import sys
    import csv
    
    fooreader = csv.reader(open('nsc_list.csv', 'rb'), delimiter = ',', quotechar = "\'")
    
    def generate_bic(sort_code):
    	flag = True
    	for row in fooreader:
    		value = row[0]
    		if value == sort_code:
    			bic = row[1]
    			print bic
    			print type(bic)
    			flag = False
    			return bic
    	print flag
    			
    generate_bic('990639')
    generate_bic('990658')
    generate_bic('990639')
    generate_bic('990637')
    generate_bic('906603')
    generate_bic('933341')
    

    And this is the output:
    IPBSIE2DXXX
    <type 'str'>
    IPBSIE2DXXX
    <type 'str'>
    True
    True
    True
    True
    

    What's interesting here is that for sort code 990639 is correctly resolved when first called but when called again is not.

    I may have gone wrong with my logic so feel free to correct!


  • Advertisement
  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    Ah. The problem is that your csv.reader is an iterable, which means that you don't start from the top of the file each time you call the function; you resume after the last line that was read before the function last returned.

    You're going to have to open the csv.reader each time you use it (and close it again!), or find a way to rewind it to the start of the file. If I get a chance later I'll have a look at the docs for it and give you more detail.


  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    Thinking some more about it: better than re-opening the file each time would be to cache its contents in a list:
    import sys
    import csv
    
    fooreader = csv.reader(open('nsc_list.csv', 'rb'), delimiter = ',', quotechar = "\'")
    foolist = [row for row in fooreader]
    
    def generate_bic(sort_code):
    	for row in foolist:
    		value = row[0]
    		if value == sort_code:
    			bic = row[1]
    			return bic
    


  • Registered Users Posts: 416 ✭✭gouche


    Thanks OscarBravo!

    If I move opening the file inside the function it works. But if I understand correctly this opens the file and keeps it in memory each time function is called?

    I had a quick look and there doesn't seem to be a close option for csv.reader.

    Looks like your solution to store contents of the file in a list works well though.

    Thanks for your help!


  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    An even more efficient approach would be to build a dictionary from the csv file, and drop the function:
    foodict = {}
    fooreader = csv.reader(open('nsc_list.csv', 'rb'), delimiter=',', quotechar="\'")
    for row in fooreader:
        foodict[row[0]] = row[1]
    

    Then just use foodict[sort_code] instead of calling a generate_bic() function.


  • Registered Users Posts: 1,509 ✭✭✭Donnelly117


    Something like

    fooreader.seek(0)

    should reset back to the start of the CSV no?


  • Advertisement
  • Hosted Moderators Posts: 3,331 ✭✭✭Splinter


    Something like

    fooreader.seek(0)

    should reset back to the start of the CSV no?
    wouldn't this just keep resetting on the first entry it finds though?


  • Technology & Internet Moderators Posts: 28,792 Mod ✭✭✭✭oscarBravo


    Something like

    fooreader.seek(0)

    should reset back to the start of the CSV no?

    fooreader is a csv.reader instance; it's an iterator, not a file-like object, and it doesn't provide a seek() method.


Advertisement