logic behind the assert syntax?

Jeremy Hylton jeremy at beopen.com
Mon Aug 28 18:50:56 EDT 2000


Greg Landrum <glandrum at my-deja.com> writes:

> Today, whilst writing some testing code, I ran across the following
> little peculiarity with assert:
>  >>> assert 1==0,'foo'
>  Traceback (innermost last):
>    File "<stdin>", line 1, in ?
>  AssertionError: foo
> That's what I expect, but this::
>  >>> assert (1==0,'foo')
>  >>>
> strikes me as a bit odd.

It shouldn't.  The first thing after "assert" is an expression.  You
can put any expression there, even a tuple.
 
> Based upon an analogy to the print statement, I understand what is
> happening here:  assert sees a tuple when you put parens around it
> and decides everything is hunky dory.  I don't like it, but I think
> that I get it.
> 
> Of course, I get completely confused again when I try and apply my
> newfound "understanding" to other statements.

Not too fast :-).  You should not apply understanding you've gained
about one statement to others haphazardly.  Are you sure you
understand why assert works the way it does?

assert is special, because the assert statement can take a comma as
part of its syntax.  When Python sees two expression separated by
commas outside of assert (and the handful of other statements that
except commas), you should think of lists of things, e.g:

   [1,2,3]
   (1,2,3)
   {'a': 1, 'b': 2}

If an expression contains a comma, all else being equal, Python is
going to treat it as a tuple, e.g.:

   a = 1, 2
   b = (1, 2)
   a == b

The parens are just there to make things more readable -- and to
disambiguate when the comma could be interpreted as part of a
statement (like assert).

> 
> so
> assert 1,'foo'
> and
> assert (1,'foo')
> do different things.

Yes, because assert consumes the comma in the first case.

> 
> print 1,'foo'
> and
> print (1,'foo')
> do different things.

Yes, because print consumes the comma in the first case.

> 
> but
> return 1,'foo'
> and
> return (1,'foo')
> do the same thing.

Yes, because return does not consume the comma.  Since the comma is
not significant to return, it is treated as tuple creation.

> 
> also
> a = 1,'foo'
> and
> a = (1,'foo')
> are equivalent.

Yes, because assignment does not consume the comma.

> 
> weird.

Perfectly straightforward :-).  You need to know enough of the
language grammar to know which statements expect commas and which do
not. 

> 
> continuing to screw around, I tried:
>  >>> (1,'foo') == 1,'foo'
>  (0, 'foo')
> which seemed odd... 

You need to watch out for operator precedence.  I'll add some parens
that make clear what is going on:

    ((1, 'foo') == 1), 'foo'

This means the same as:

    left = (1, 'foo') == 1
    right = 'foo'
    (left, right)

>                     so I tried:
>  >>> (1,'foo') == (1,'foo')
>  1
> this made sense. 

It sure did.

>                   But then:
>  >>> 1,'foo' == 1,'foo'
>  (1, 0, 'foo')
> confused me again until I realized that this was:
>  1,('foo'==1),'foo'
> 

It's the operator precendence again.

> Now my head is in a bit of a whirl...  Python normally strikes me as
> so logical and reasonable, but this has thrown me for a loop.
> 
> Can someone clear this up a bit?
> 

I hope I did.  Ask some more questions if not.

One thing that might help.  These are some statements that give
special meaning to a comma.  For these statements, the comma demarcates
different parts of the expression:

    print -- separates different objects to be printed
    raise -- separates the exception type from its value
    except -- the same
    import -- separates the names in a list of modules to import
    global -- separates the names in a list of global variables
    exec -- separates the different objects to use as namespaces
    assert -- separates the assertion test from the error message

-- Jeremy Hylton <http://www.python.org/~jeremy/>





More information about the Python-list mailing list