Ex 48 trouble converting string-number into integer

I really thought it would convert this time. Does anyone see why it wasn’t able to convert?

I can be wrong but I believe the top section is good. it’s at the very bottom, in the elif section where I’m having trouble

this is my code:

lexicon = {
    'north': 'direction',
    'south': 'direction',
    'east': 'direction',
    'west': 'direction',
    'go': 'verb',
    'kill': 'verb',
    'eat' : 'verb',
    'the': 'stop',
    'in': 'stop',
    'of': 'stop',
    'bear': 'noun',
    'princess': 'noun',
    '1234': 'number',
    '3': 'number',
    '91234': 'number',
    'ASDFADFASDF': 'error',
    'bear': 'noun',
    'IAS': 'error',
    'princess': 'noun',
            }

def convert_number(s):
    try:
        return int(s)
    except ValueError:
        return None

def scan(sentence):
       words = sentence.split()
       result = []

    for word in words:
      
        if lexicon[word] == 'noun' or 'verb' or 'stop' or 'error':
           pair = (lexicon[word], word)
           result.append(pair)

here’s the part I’m having issues with and I can’t figure out why

basically, I say, call the value associated to the key [word] from the dict lexicon and if it equals 'number' run the branches in this block of code

than I convert the string-number (‘1234’) using the convert_number function and pass it to integer

than I create a tuple pair from lexicon[word] and integer, which should print out: ('number', 1234). Than pass this tuple to number_pair and finally append number_pair to result

    `elif lexicon[word] == 'number':
        integer = convert_number(word)
        number_pair = (lexicon[word], integer)
        result.append(number_pair)`

return result

I’ve been going at this for many hours trying to convert the string-number passed to the scan function argument into an integer. I really thought I would get it this time but I still got an AssertionError.

Does anybody see where I went wrong in this?

this is the assertion error (as you can see the, actual object is still a string and the desired object is an integer):

AssertionError: Lists differ: ['(number)'], '1234')] != [('number', 1234)]

I think you’re close but you have two things to change in your code before you can get it. I’ll give you a soft fix so you can try to solve it on your own, then if you still can’t get it come back with what you’ve learned trying to do it.

Ok, first up this line of code:

if lexicon[word] == 'noun' or 'verb' or 'stop' or 'error':

You can’t really do that in any programming language, and even in English it’s not right. To do that you have to be explicit about every logical condition, so you have to rewrite it as:

if lexicon[word] == 'noun' or lexicon[word] == 'verb' or lexicon[word] == 'stop' or lexicon[word] == 'error':

Now, you can simulate what you want using this:

if lexicon[word] in ['noun', 'verb', 'stop', 'error']:

The in keyword just asks if the value on the left of in is in the list or dict on the right. The second thing is I don’t think the code you posted matches your description of the problem. Can you edit your post and put in the real code? And then, just look at what the assertion says:

AssertionError: Lists differ: ['(number)'], '1234')] != [('number', 1234)]

I read that as "lists differ one list has STRING, STRING the other has STRING, NUMBER.

See the quotes around the ‘1234’ on the left, but none on the right?

1 Like

okay I see what you mean about the logical condition. However, why didn’t nosetests flag it?

Since nosetests didn’t show any errors about the logical condition, I assumed it could be done (lol, It seems I was wrong).

But since I didn’t think it was a problem, that is why I didn’t mention it as a problem. I believe this is what you mean when you say, “I don’t think the code you posted matches your description of the problem.”

I will edit this post and show my full code 1st before stating the problem I’m having. hopefully, that’ll clarify the issues I’m having with my code.

Welllllllllllllllllllllll it technically is valid, but definitely not what you think it does. Here’s me playing with it:

>>> x = 1
>>> x == 2 or 'hi' or 'what' or 30
'hi'
>>>

The result of doing a logical condition in Python is not True or False, but the first value that causes it to be true or false. At least that’s my understanding of their definition of it (which I think many times Python pros can’t really explicitly lay out). The reason it’s like this is so you can initialize variables that may or may not be initialized:

def mything(x=None):
    if not x: x = 100

So let’s say you’re doing a default like that. You want people to give you x, and if they don’t then you can set it to 100. Using the or trick above you can do this instead:

def mything(x=None):
    x = x or 100

Now, why would you want to do this? You could just say mything(x=100). For most defaults that’s how you’d do it, but that will fail whenever you do a {} or [] type as a default value to a function. If you did this:

def createit(attributes={}):
   # do something with attributes

Then you’d be surprised when it seems like you have one global dict and not a new dict on every function call. Take a look at an example of me doing that:

Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import random
>>> x = random.randint()
>>> x = random.randint(0,1000)
>>> def createit(attributes={}):
...     print("Attributes at top: ", attributes)
...     attributes['random'] = random.randint(0,1000)
...     print("Attributes after change: ", attributes)
... 
>>> createit()
Attributes at top:  {}
Attributes after change:  {'random': 480}
>>> createit()
Attributes at top:  {'random': 480}
Attributes after change:  {'random': 197}
>>> createit()
Attributes at top:  {'random': 197}
Attributes after change:  {'random': 830}
 

See how it looks like the ‘random’ key in attributes is resurrected from the dead on each function call? That’s because Python makes a single copy of the default {} for attribute, so every time the function runs you don’t get a new {} you get the original. The only way to solve that is to change the function like this:

def createit(attributes=None):
    attributes = attributes or {}
    print("Attributes at top: ", attributes)
    attributes['random'] = random.randint(0,1000)
    print("Attributes after change: ", attributes)

When you do that then it works as you expected:

>>> createit()
Attributes at top:  {}
Attributes after change:  {'random': 759}
>>> createit()
Attributes at top:  {}
Attributes after change:  {'random': 684}
>>> createit()
Attributes at top:  {}
Attributes after change:  {'random': 732}
1 Like

I’m gonna be honest. I got a little lost in your explanation above. I somewhat understand what you meant and understood the code you gave, but I don’t know if I comprehended the exact point you were trying to make.

I assume ultimately you meant, that when using the or expression to juxtapose 1 element with a list of elements equally (as I initially tried in my code), Python will read the line and send the 1st value that it reads as True or False. Hence, this was the reason why nosetests didn’t flag this line in my cod; Because Python returned the 1st value it read as True or False.

I did however adopt the in token into my code and I believe I got that line working properly this time.

nosetests did flag my code with a different AssertionError however:

AssertionError: ([('number', 3), ('number', 91234)],) != [('number', 3),('number', 91234)] (

By reading the error, I gather that this time I managed to convert the strings '3' and '91234' into integers but my code is being flagged with an error for the extra , seen near the end in 91234)],).

I don’t understand why that comma is there though. I looked through my code and I didn’t place any comma as it shows in this error.

here is my code:

lexicon = {
    'north': 'direction',
    'south': 'direction',
    'east': 'direction',
    'west': 'direction',
    'go': 'verb',
    'kill': 'verb',
    'eat' : 'verb',
    'the': 'stop',
    'in': 'stop',
    'of': 'stop',
    'bear': 'noun',
    'princess': 'noun',
    '1234': 'number',
    '3': 'number',
    '91234': 'number',
    'ASDFADFASDF': 'error',
    'bear': 'noun',
    'IAS': 'error',
    'princess': 'noun',
            }

def convert_number(s):
    try:
        return int(s)
    except ValueError:
        return None

def scan(sentence):
    words = sentence.split()
    result = []

    for word in words:
      
        if lexicon[word] in  ['direction', 'noun', 'verb', 'stop', 'error']:
            pair = (lexicon[word], word)
            result.append(pair)

        elif lexicon[word] in 'number':
            integer = convert_number(word)
            number_pair = (lexicon[word], integer)
            result.append(number_pair)
    
    return result

What am I missing? I noticed that the '1234' , 'number' (STRING: STRING) passed to the scan function wasn’t flagged. I assume this is because it converted successfully into STRING, NUMBER

I’m happy to see that the conversion went down successfully, but I can’t place where that extra , is coming from.

Closer, well for my description I was explaining why that or/or/or syntax isn’t an error. You got the gist of it though.

Now, to answer, the assertion on the left is a structure like this:

tuple(list(tuple tuple))

So you have ( [ () () ] )

But on the right you have:

list(tuple tuple)

So it’s like:

[ (), () ]

I suspect you’ve got the test wrong rather than the code. What you can do is pop this at the top of your script:

import pdb

Then right before this assert do this:

pdb.set_trace()

That’ll pause the Python there and you can then you can use the Python Debugger to print things out and work with the code to see what it’s doing there.

https://docs.python.org/3/library/pdb.html

That’ll let you print things out, analyze variables, run python code to try a fix, step through, etc.

1 Like