Python GAE—;奇怪的实例变量行为

Python GAE—;奇怪的实例变量行为,python,google-app-engine,Python,Google App Engine,在GAE上,我使用hmac为AWS API请求生成签名。我的代码原来是这样的: import urllib import urllib2 import time import hmac import base64 from hashlib import sha256 as sha256 class AmazonProductAdvertisingAPI: secret_access_key = '...' my_hmac = hmac.new(secret_access_ke

在GAE上,我使用
hmac
为AWS API请求生成签名。我的代码原来是这样的:

import urllib
import urllib2
import time
import hmac
import base64
from hashlib import sha256 as sha256

class AmazonProductAdvertisingAPI:

    secret_access_key = '...'
    my_hmac = hmac.new(secret_access_key, digestmod=sha256)

    def get_signed_url(self, params):

        ....

        # Sign it
        self.my_hmac.update('GET' + "\n" + server + "\n" + path + "\n" + paramstring)
        urlstring = urlstring + "&Signature=" + \
            urllib.quote(base64.encodestring(self.my_hmac.digest()).strip())

        return urlstring
有了这个,我发现API请求(使用
get\u signed\u URL
给出的URL)当且仅当请求是实例的“冷启动”,例如,在我部署代码并第一次运行它之后

但是,随后的请求失败,AWS声称签名无效。通过将
my_hmac
移动到方法内,使其成为方法内的变量,而不是类内的实例变量,可以解决此问题

...
def get_signed_url(self, params):
    my_hmac = hmac.new(self.secret_access_key, digestmod=sha256)
    ...

我有一个问题:为什么?

你的
我的_hmac
变量是一个类变量;由类的所有实例共享的一个

...
def get_signed_url(self, params):
    my_hmac = hmac.new(self.secret_access_key, digestmod=sha256)
    ...
这意味着,对于对
.get\u signed\u url()
的每次调用,
self.my\hmac.update()
调用都会跨实例向摘要中添加数据,并全局添加到应用程序中

由于您只想计算一个字符串的摘要(GET…字符串),而不是累加地计算所有字符串,因此必须为要计算的每个新摘要创建一个新的
hmac
对象

注意:

使用字符串arg更新哈希对象。重复调用相当于连接所有参数的单个调用:
m.update(a);m、 update(b)
相当于
m.update(a+b)


您的
my_hmac
变量是一个类变量;由类的所有实例共享的一个

...
def get_signed_url(self, params):
    my_hmac = hmac.new(self.secret_access_key, digestmod=sha256)
    ...
这意味着,对于对
.get\u signed\u url()
的每次调用,
self.my\hmac.update()
调用都会跨实例向摘要中添加数据,并全局添加到应用程序中

由于您只想计算一个字符串的摘要(GET…字符串),而不是累加地计算所有字符串,因此必须为要计算的每个新摘要创建一个新的
hmac
对象

注意:

使用字符串arg更新哈希对象。重复调用相当于连接所有参数的单个调用:
m.update(a);m、 update(b)
相当于
m.update(a+b)


啊!第一次使用Python。所以,这是一个类变量。如何创建实例变量?在init内?在
\uuuuu init\uuuuu
内,是。方法中分配给self.someattribute的任何内容都是设置实例变量。明白了。谢谢你的帮助!不客气!请注意,在这种特定情况下,您希望使用局部变量,而不是实例变量;您不想计算
GET的摘要。。。1
+
获取。。。2
+
获取。。。3
要么。Doh!第一次使用Python。所以,这是一个类变量。如何创建实例变量?在init内?在
\uuuuu init\uuuuu
内,是。方法中分配给self.someattribute的任何内容都是设置实例变量。明白了。谢谢你的帮助!不客气!请注意,在这种特定情况下,您希望使用局部变量,而不是实例变量;您不想计算
GET的摘要。。。1
+
获取。。。2
+
获取。。。3