【问题标题】:How to deal with globals in modules?如何处理模块中的全局变量?
【发布时间】:2015-02-27 04:08:12
【问题描述】:

我尝试为 OpenWeatherMap 进行非阻塞 api 调用,但我的问题是:

当我对文件进行测试并运行它时,global api 生效,但是在导入函数时,global 不再工作,api 没有变化:api = ""?

在声明函数后,我输入了global api,然后当我使用print 'The API link is: ' + api 时,我得到了确切的api,但global dident 生效了!

这里是代码:https://github.com/abdelouahabb/tornadowm/blob/master/tornadowm.py#L62

我做错了什么?

当我导入文件时:

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]: ''

执行文件而不是导入文件时:

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'

编辑:这里是代码,如果 Git 更新了:

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''

【问题讨论】:

  • 当你只在一个地方使用这个变量时,为什么要使用全局变量?您是否在代码示例中未显示的地方使用它?
  • 另外,您的 args 在技术上没有在您的 def 中定义,当导入时应该会引发错误
  • 刚刚编辑了问题,现在,如您所见,如果我运行文件,我会更改global,但是在导入它时,global 不会被触及,python 2.7.9
  • @Abdelouahab 为了后代,下次尝试将代码的重要部分直接粘贴到您的问题中,因为您的链接可能会损坏或更改,并且您希望您的问题仍然有意义几年后,来自谷歌或类似网站的用户:)
  • @Jivan 谢谢你,我刚做了,所以万一它丢失了,或者 git 改变了,所以人们总会得到它有用的:)

标签: python function global-variables python-import


【解决方案1】:

这是使用global的副作用。

当您执行from tornadowm import * 时,您的forecast() 函数可以比喻为“独立”,不再与您的全局空间“硬链接”。

为什么?因为您对全局api 所做的任何影响都将在您的函数中“结束”,并且您的全局空间中api = "" 的定义将优先。

另外,作为旁注,使用from something import * 不是一个好习惯。您应该使用from tornadowm import forecast 甚至更好,import tornadown,然后使用tornadowm.forecast()

更好的是,我刚刚注意到您的 forecast() 函数没有返回任何内容。从技术上讲,它不再是function,而是procedure(过程就像一个函数,但它什么也不返回,它只是“做”一些事情)。

您应该在此函数中定义api,然后从中定义return api,而不是使用global。像这样:

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

然后

import tornadowm
api = tornadown.forecast(something)

你已经完成了。

【讨论】:

  • 技术上我们的答案相同,但您的答案更详细且易于理解
  • 那么,这意味着在处理导入时要避免global
  • 当您尝试使用from tornadowm import forecast 而不是* 时,它会说什么?
  • 现在它在使用它的方法导入模块时工作了,不知道这个!
  • @Jivan,你知道吗?那是return api 其实我也在想:) 哈哈
【解决方案2】:

全局变量仅对定义它们的模块是全局的。因此,通常情况下,您希望在调用 forecast 时更改 tornadowm.api,但在其他命名空间中不会更改 api

import * 有助于您理解问题。这会将api(以及其他名称)导入导入命名空间。这意味着apitornadowm.api 最初指向同一个对象。但是这两个名字没有任何联系,所以调用forecast()只会改变tornadowm.api,现在这两个名字指向不同的对象。

为避免这种情况,请勿使用import *。无论如何,这是不好的做法,这只是原因之一。相反,import tornadowm 并以tornadowm.api 访问导入模块中的变量。

【讨论】:

  • 啊,我现在明白了,在过去,我认为使用import * 只是为了可读性(知道我们在这个方法中使用了哪个模块),而不是让方法冲突!跨度>
  • @Abdelouahab 请注意,您单独指出的这两个原因足以证明不使用global 是合理的。但是你刚刚发现了第三个原因:)
  • 还有一个重要原因!我什至尝试使用list.append() 作为一个技巧,但即使那个没有帮助,所以似乎我得到了一个新的隐藏功能!谢谢你^_^
【解决方案3】:

恐怕这是因为 global 在模块内耦合,当您 from tornadowm import * 时,您已经导入了 api 名称,但 global api不会在另一个模块中产生任何影响。

【讨论】:

  • 啊,就像@jivan 说的,它只是看到的函数,而不是全局变量
  • @Abdelouahab,您在某种程度上是正确的。您实际上可能会看到 kindall 的答案,他已经详细解释了您应该能够理解 global 在 Python 中的工作原理
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 2013-01-28
  • 2012-11-05
  • 2015-03-07
相关资源
最近更新 更多