92

How can I make a variable inside the try/except block public?

import urllib.request

try:
    url = "http://www.google.com"
    page = urllib.request.urlopen(url)
    text = page.read().decode('utf8')
except (ValueError, RuntimeError, TypeError, NameError):
    print("Unable to process your request dude!!")

print(text)

This code returns an error

NameError: name 'text' is not defined

How can I make the variable text available outside of the try/except block?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • 1
    What will be `text` if `page = urllib.request.urlopen(url)` will raise an exception? If you want to set it with some value you can do it in the except scope or outside the `try except` block. – Kobi K Sep 04 '14 at 13:34
  • 2
    `text` is the be the markup of the url. –  Sep 04 '14 at 13:35
  • 2
    In the `except` case `text` is *never assigned*. You could set `text = None` in that block or before the `try`. This isn't a scope problem. – jonrsharpe Sep 04 '14 at 13:35
  • 1
    if the error mentioned in the question is raised without going through the print statement in the except block then, I think the exception is not getting caught – Ashoka Lella Sep 04 '14 at 13:41
  • 2
    // , According to http://stackoverflow.com/questions/17195569/using-a-variable-in-a-try-catch-finally-statement-without-declaring-it-outside, Python does not have a block scope. – Nathan Basanese Aug 31 '15 at 20:28

3 Answers3

133

try statements do not create a new scope, but text won't be set if the call to url lib.request.urlopen raises the exception. You probably want the print(text) line in an else clause, so that it is only executed when there is no exception.

try:
    url = "http://www.google.com"
    page = urllib.request.urlopen(url)
    text = page.read().decode('utf8')
except (ValueError, RuntimeError, TypeError, NameError):
    print("Unable to process your request dude!!")
else:
    print(text)

If text needs to be used later, you really need to think about what its value is supposed to be if the assignment to page fails and you can't call page.read(). You can give it an initial value prior to the try statement:

text = 'something'
try:
    url = "http://www.google.com"
    page = urllib.request.urlopen(url)
    text = page.read().decode('utf8')
except (ValueError, RuntimeError, TypeError, NameError):
    print("Unable to process your request dude!!")

print(text)

or in the else clause:

try:
    url = "http://www.google.com"
    page = urllib.request.urlopen(url)
    text = page.read().decode('utf8')
except (ValueError, RuntimeError, TypeError, NameError):
    print("Unable to process your request dude!!")
else:
    text = 'something'

print(text)
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    I think the OP wants a default value for `text` in case there is an `exception`. so maybe updating this answer with default value outside the `try except` scope or inside the else will help him. – Kobi K Sep 04 '14 at 13:38
  • 7
    In the last snippet `text` will always eventually be assigned `'something'` if no exception – 4xy Nov 16 '17 at 19:03
  • 6
    "try statements do not create a new scope" this cleared up a lot of things for me, +1 – Silidrone Jul 13 '20 at 08:27
  • 1
    the "else" clause didn't work for me, but the initial value did. :D – santma Dec 10 '20 at 23:39
  • In the 3rd example, aside from the problem mentioned by @4xy, `print(text)` would still cause the original `NameError` if `page.read().decode('utf8')` raises an exception. It would only work if `text = 'something'` is moved into the `except` block. – Qiang Xu May 09 '21 at 21:04
  • Thank you! This one line "text won't be set if the call to url lib.request.urlopen raises the exception." cleared up the confusion I had for ages! – nabil.adnan1610 Feb 01 '22 at 22:45
8

As answered before there is no new scope introduced by using try except clause, so if no exception occurs you should see your variable in locals list and it should be accessible in current (in your case global) scope.

print(locals())

In module scope (your case) locals() == globals()

4xy
  • 3,494
  • 2
  • 20
  • 35
7

Just declare the variable text outside try except block,

import urllib.request
text =None
try:
    url = "http://www.google.com"
    page = urllib.request.urlopen(url)
    text = page.read().decode('utf8')
except (ValueError, RuntimeError, TypeError, NameError):
    print("Unable to process your request dude!!")
if text is not None:
    print(text)
Nishant Nawarkhede
  • 8,234
  • 12
  • 59
  • 81
  • 7
    // , Why would this be necessary? Python does not have a separate block-level scope for this `try` and `except`, AFAIK, and according to http://stackoverflow.com/questions/17195569/using-a-variable-in-a-try-catch-finally-statement-without-declaring-it-outside. – Nathan Basanese Aug 31 '15 at 20:26
  • @NathanBasanese It may be necessary, if your try/except block resides in a loop and your except block contains the `continue` statement without defining the variable there. – stackprotector Sep 01 '23 at 11:05