Abdelouahab
Abdelouahab

Reputation: 7539

How to deal with globals in modules?

I try to make a non blocking api calls for OpenWeatherMap, but my problem is:

When i was doing tests on the file, and run it, the global api was taking effect, but when importing the function, global dont work anymore, and api dident change: api = ""?

Just after declaring the function i put global api, and then when I use print 'The API link is: ' + api I get the exact api, but global dident took effect!

Here is the code: https://github.com/abdelouahabb/tornadowm/blob/master/tornadowm.py#L62

What am I doing wrong?

When I import the file:

from tornadowm import *
forecast('daily', q='london', lang='fr')
The API link is: http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london
api
Out[5]: ''

When executing the file instead of importing it:

runfile('C:/Python27/Lib/site-packages/tornadowm.py', wdir='C:/Python27/Lib/site-packages')

forecast('daily', q='london', lang='fr')
The API link is: http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london

api
Out[8]: 'http://api.openweathermap.org/data/2.5/forecast/daily?lang=fr&q=london'

Edit: here is the code, if the Git got updated:

from tornado.httpclient import AsyncHTTPClient
import json
import xml.etree.ElementTree as ET

http_client = AsyncHTTPClient()
url = ''
response = ''
args = []
link = 'http://api.openweathermap.org/data/2.5/'
api = ''
result = {}
way = ''


def forecast(way, **kwargs):
    global api
    if way in ('weather', 'forecast', 'daily', 'find'):
        if way == 'daily':
            way = 'forecast/daily?'
        else:
            way += '?'
        for i, j in kwargs.iteritems():
            args.append('&{0}={1}'.format(i, j))
        a = ''.join(set(args))
        api = (link + way + a.replace(' ', '+')).replace('?&', '?')
        print 'The API link is: ' + api

        def handle_request(resp):
            global response
            if resp.error:
                print "Error:", resp.error
            else:
                response = resp.body

        http_client.fetch(api, handle_request)
    else:
        print "please put a way: 'weather', 'forecast', 'daily', 'find' "


def get_result():
    global result
    if response.startswith('{'):
        print 'the result is JSON, stored in the variable result'
        result = json.loads(response)

    elif response.startswith('<'):
        print 'the result is XML, parse the result variable to work on the nodes,'
        print 'or, use response to see the raw result'
        result = ET.fromstring(response)

    else:
        print '''Sorry, no valid response, or you used a parameter that is not compatible with the way!\n please check http://www.openweathermap.com/api for more informations''

Upvotes: 1

Views: 64

Answers (3)

Jivan
Jivan

Reputation: 23068

It's the side effect of using global.

When you do from tornadowm import * your forecast() function is, we could say metaphorically, "on its own" and is not "hard-linked" to your global space anymore.

Why? Because any effect you make on your global api will "end" with your function, and the definition of api = "" in your global space will take precedence.

Also, as a side note, it's not considered a good practice to use from something import *. You should do from tornadowm import forecast or even better, import tornadown and then use tornadowm.forecast().

  • OR

Even better, I just noticed your forecast() function doesn't return anything. Which technically makes it not a function anymore, but a procedure (a procedure is like a function but it returns nothing, it just "does" stuff).

Instead of using a global, you should define api in this function and then return api from it. Like this:

def forecast(blablabla):
    api = "something"
    blablabla
    return api

And then

import tornadowm
api = tornadown.forecast(something)

And you're done.

Upvotes: 3

kindall
kindall

Reputation: 184121

Globals are global only to the module they're defined in. So, normally, you would expect tornadowm.api to be changed when you call forecast, but not api in some other namespace.

The import * is contributing to your understanding of the problem. This imports api (among other names) into the importing namespace. This means that api and tornadowm.api initially point to the same object. But these two names are not linked in any way, and so calling forecast() changes only tornadowm.api and now the two names point to different objects.

To avoid this, don't use import *. It is bad practice anyway and this is just one of the reasons. Instead, import tornadowm and access the variable in the importing module as tornadowm.api.

Upvotes: 2

Anzel
Anzel

Reputation: 20553

I'm afraid this is because global is coupled within module, by the time you from tornadowm import * you have imported the api name, but the global api won't take any effects within another module.

Upvotes: 1

Related Questions