为什么这个 class 和相应的属性在请求之间没有被破坏?
Why is this class and corresponding attribute not being destroyed between requests?
我完全无法理解这种行为。我昨天或前一天问了一个问题,认为这是 bottle.py 的问题,但在尝试了各种可能的解决方案之后,甚至将我的应用程序转换为 Flask,我已经将行为确定为一个非常简单的行为,class,但我不知道为什么会这样。这让我很困惑,但如果 任何人 可以解释一下,我真的很想理解这一点。
好的,所以首先我有一个名为 Page 的 class,它稍微简化了模板的设置,这是令人讨厌的 class:
class Page:
"""The page object constructs the webpage and holds associated variables and templates"""
def __init__(self, template=None, name = '', title='',template_vars={}, stylesheets=[], javascript=[]):
# Accepts template with or without .html extension, but must be added for lookup
self.stylesheet_dir = '/css'
self.javascript_dir = '/js'
self.template = template
self.template_vars = {}
self.name = name
self.title = title
self.stylesheets = stylesheets
self.javascript = javascript
self.template_vars['debug'] = _Config.debug
self.template_vars['title'] = self.title
self.template_vars['stylesheets'] = self.stylesheets
self.template_vars['javascript'] = self.javascript
def render(self):
"""Should be called after the page has been constructed to render the template"""
if not self.template.endswith(_Config.template_extension):
self.template += '.' + _Config.template_extension
if not self.title:
if self.name:
self.title = _Config.website + _Config.title_delimiter + self.name
else:
# If title not given use template name
self.title = _Config.website + _Config.title_delimiter + self.template.rstrip('.html')
try:
template = env.get_template(self.template)
except AttributeError:
raise (AttributeError, 'template not set')
rendered_page = template.render(self.template_vars)
return rendered_page
def add_stylesheet(self, name, directory=None):
# Sanitize name
if not name.endswith('.css'):
name += '.css'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.stylesheet_dir
self.template_vars['stylesheets'].append(directory + '/' + name)
def add_javascript(self, name, directory=None):
# Sanitize name
if not name.endswith('.js'):
name += '.js'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.javascript_dir
self.template_vars['javascript'].append(directory + '/' + name)
这是出现问题的路线示例:
@route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account')
page.add_javascript('create_account.js')
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
# Omitted
问题出在方法 Page.add_javascript() 上。下次我转到 /create_account 页面时,它不会创建新的 Page 对象,而是重用旧的。我知道这一点,因为如果我两次访问该页面,我将在返回的 html 文档中有两个完整的 create_account.js(模板只是运行一个 for 循环并为传入的任何 js 文件创建一个标记那个清单)。如果我去 3 次,它会被列出 3 次,40 次,40 次等等。但是现在,如果我只是将其更改为使用初始化程序而不是 add_javascript 方法,问题就会消失。
@route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account', javascript=['create_account.js'])
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
但是我怀疑还是有问题,为了我自己的理智,我需要了解这到底是怎么回事。 add_javascript 方法在同一个页面对象上被调用两次的幕后可能发生了什么?在创建页面对象的 new 实例后立即 调用该方法,它可能从哪里获取 template_vars 的旧内容?
问题是您为 Page.__init__
函数使用了可变默认值。参见 http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments。
所以你 do 在每个请求上得到一个新的 Page
实例,但是保存你的 javascript 等的 lists/dictionaries 是重新使用过。
将 list/dict 默认参数值替换为 None
,检查 __init__
中的 None
。
我完全无法理解这种行为。我昨天或前一天问了一个问题,认为这是 bottle.py 的问题,但在尝试了各种可能的解决方案之后,甚至将我的应用程序转换为 Flask,我已经将行为确定为一个非常简单的行为,class,但我不知道为什么会这样。这让我很困惑,但如果 任何人 可以解释一下,我真的很想理解这一点。
好的,所以首先我有一个名为 Page 的 class,它稍微简化了模板的设置,这是令人讨厌的 class:
class Page:
"""The page object constructs the webpage and holds associated variables and templates"""
def __init__(self, template=None, name = '', title='',template_vars={}, stylesheets=[], javascript=[]):
# Accepts template with or without .html extension, but must be added for lookup
self.stylesheet_dir = '/css'
self.javascript_dir = '/js'
self.template = template
self.template_vars = {}
self.name = name
self.title = title
self.stylesheets = stylesheets
self.javascript = javascript
self.template_vars['debug'] = _Config.debug
self.template_vars['title'] = self.title
self.template_vars['stylesheets'] = self.stylesheets
self.template_vars['javascript'] = self.javascript
def render(self):
"""Should be called after the page has been constructed to render the template"""
if not self.template.endswith(_Config.template_extension):
self.template += '.' + _Config.template_extension
if not self.title:
if self.name:
self.title = _Config.website + _Config.title_delimiter + self.name
else:
# If title not given use template name
self.title = _Config.website + _Config.title_delimiter + self.template.rstrip('.html')
try:
template = env.get_template(self.template)
except AttributeError:
raise (AttributeError, 'template not set')
rendered_page = template.render(self.template_vars)
return rendered_page
def add_stylesheet(self, name, directory=None):
# Sanitize name
if not name.endswith('.css'):
name += '.css'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.stylesheet_dir
self.template_vars['stylesheets'].append(directory + '/' + name)
def add_javascript(self, name, directory=None):
# Sanitize name
if not name.endswith('.js'):
name += '.js'
if name.startswith('/'):
name = name.lstrip('/')
if not directory:
directory = self.javascript_dir
self.template_vars['javascript'].append(directory + '/' + name)
这是出现问题的路线示例:
@route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account')
page.add_javascript('create_account.js')
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
# Omitted
问题出在方法 Page.add_javascript() 上。下次我转到 /create_account 页面时,它不会创建新的 Page 对象,而是重用旧的。我知道这一点,因为如果我两次访问该页面,我将在返回的 html 文档中有两个完整的 create_account.js(模板只是运行一个 for 循环并为传入的任何 js 文件创建一个标记那个清单)。如果我去 3 次,它会被列出 3 次,40 次,40 次等等。但是现在,如果我只是将其更改为使用初始化程序而不是 add_javascript 方法,问题就会消失。
@route('/create_account', method=['GET','POST'])
def create_account():
dbsession = db.Session()
page = Page('create account', javascript=['create_account.js'])
if request.method == 'GET':
page.template = 'create_account'
page.template_vars['status'] = None
document = page.render()
dbsession.close()
return document
elif request.method == 'POST':
但是我怀疑还是有问题,为了我自己的理智,我需要了解这到底是怎么回事。 add_javascript 方法在同一个页面对象上被调用两次的幕后可能发生了什么?在创建页面对象的 new 实例后立即 调用该方法,它可能从哪里获取 template_vars 的旧内容?
问题是您为 Page.__init__
函数使用了可变默认值。参见 http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments。
所以你 do 在每个请求上得到一个新的 Page
实例,但是保存你的 javascript 等的 lists/dictionaries 是重新使用过。
将 list/dict 默认参数值替换为 None
,检查 __init__
中的 None
。