On Tue, Nov 17, 2020 at 09:55:46AM +0000, Mark Shannon wrote:
> Hi,
> 
> I'm wondering why
> ```
> x = "value"
> try:
>     1/0
> except Exception as x:
>     pass
> ```
> 
> does not restore "value" to x after
> the `except` block.

Because try, if, for, while, with etc. don't create a new scope. Only 
two statements create a new scope: `def` and `class`.

I presume you don't also expect these to restore x after the
blocks are ended:


    x = "value"
    for x in range(100):
        pass

    with open('filename') as x:
        text = x.read()


`try...except` is no different.

If you search the archives on Python-List, going back two or four years, 
you will find extensive discussion between those who think that every 
statement with an indent should create a new scope, and those who don't. 
Apologies in advance to supporters of the "new scope" philosophy who 
might feel I am giving the idea short shrift, but my recollection is 
that they were unable to give any better justification than "but that's 
what C does" and "well, it might be useful someday to use a name 
inside a block without clobbering its existing value".

(My response to that is, just use a new variable name, it's not like 
there is a shortage.)

The only wrinkle in the case of `try...except` is that the error 
variable is deleted, even if it wasn't actually used. If you look at the 
byte-code generated, each compound try...except with an exception 
variable is followed by the equivalent of:

    err = None
    del err


There really ought to be a FAQ about this, but it has something to do 
with the exception object forming a long-lasting reference cycle. To 
avoid that, the error variable is nuked on leaving the compound block.

This is documented here:

https://docs.python.org/3/reference/compound_stmts.html#the-try-statement

although only briefly and without much detail.


> Nor does there seem to be any good technical reason for doing it this 
> way.

I expect the reason is the usual cost-benefit of "good enough". The 
effort involved in storing the old name binding and then restoring it 
afterwards is more than the benefit gained (almost zero).

This has been part of Python since Python 3.0, so if you are only just 
noticing it, that gives an idea of how rarely it comes up.


> Here's an example of restoring the value of the variable after the 
> `except` block:
> 
> >>> def f(x):
> ...     try:
> ...         1/0
> ...     except Exception as x:
> ...         pass
> ...     return x
> ...
> >>> f("hi")
> 'hi'

What Python interpreter are you using for that? This is not what happens 
in Python 3:

    # raises an exception
    UnboundLocalError: local variable 'x' referenced before assignment

or Python 2.7:

    # returns the exception object
    ZeroDivisionError('integer division or modulo by zero',)


So unless you are using some modified or alternative interpreter, I 
don't know how you got that output.



-- 
Steve
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/TIXX4P4KOA2OO7JTU3BCLNIGLIWC66M2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to