variable scope in try ... EXCEPT block.

2018-07-12 Thread aleiphoenix
suppose following code running with Python-3.4.8 and Python-3.6.5


# -*- coding: utf-8 -*-


def hello():
err = None
print('0: {}'.format(locals()))
try:
b = 2
print('1: {}'.format(locals()))
raise ValueError()
print('2: {}'.format(locals()))
except ValueError as err:
print('3: {}'.format(locals()))
pass
print('4: {}'.format(locals()))
return '', err


hello()



got output:

0: {'err': None}
1: {'err': None, 'b': 2}
3: {'err': ValueError(), 'b': 2}
4: {'b': 2}
Traceback (most recent call last):
  File "err.py", line 19, in 
hello()
  File "err.py", line 16, in hello
return '', err
UnboundLocalError: local variable 'err' referenced before assignment


But without this UnboundLocalError with Python-2.7.14


My question is, does except ... as ... create a new scope from outer block, 
causing 'err' be hidden from outer scope? Is this intentional?

Thanks.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: variable scope in try ... EXCEPT block.

2018-07-12 Thread aleiphoenix
On Thursday, July 12, 2018 at 5:45:52 PM UTC+8, Ben Bacarisse wrote:
> 
> Yes, it's intentional, but it's not exactly a scope.  In
> 
>   https://docs.python.org/3/reference/compound_stmts.html#try
> 
> -- 
> Ben.

Thank you for the reply. Never thought of this kind of problem in Python3.

On Thursday, July 12, 2018 at 6:02:27 PM UTC+8, Steven D'Aprano wrote:
> 
> You can work around this by explicitly assigning to another local 
> variable:
> 
> try:
> ...
> except Exception as e:
> err = e  # only "e" will be deleted when we exit the block
> 

I ended up with workaround like this.

> This is necessary in Python 3 (but not Python 2) because exception 
> objects form a reference cycle with something (the traceback?) which is a 
> big, heavyweight object. Allowing random exception objects to stay alive 
> for long periods was consuming unacceptable amounts of memory, so it was 
> decided to hit this problem with a hammer and fix it in the simplest, 
> although least elegant, way: just delete the exception when leaving the 
> except block.
> 
> You can see the disassembled byte-code here. Here's the output from 
> Python 3.5:
> 
> [assembly code]

And thanks for the kind answer here. Guest I should dig into Python3 deeper.

On Friday, July 13, 2018 at 6:10:57 AM UTC+8, [email protected] wrote:
> 
> Is there a downside of implementing
> it similarly to this (untested):
> 
>   # generate a unique name for __except_N
>   except E as __except_N:
> if 'N' in locals() or N in globals():
>   __original_N = N
> 
> N = __except_N
> try:
>   foo()
> finally:
>   del __except_N
> 
>   if '__original_N' in locals():
> N = __original_N
> del __original_N
>   else:
> del N

I prefer it like this. Thus, like said Python3 have chosen "fix it in the 
simplest, although least elegant", I guess.
-- 
https://mail.python.org/mailman/listinfo/python-list