为什么请求之间不会销毁此类和相应的属性?

时间:2015-10-08 00:27:10

标签: python class oop http bottle

我根本无法理解这种行为。我在昨天或前一天问了一个问题,之前认为这是关于bottle.py的问题,但在尝试了各种可能的解决方案之后,甚至将我的应用程序转换为烧瓶,我已经将行为精确定位到一个非常简单的类,但是我不知道为什么会这样。这让我感到困惑,但如果任何人能够对此有所了解,我真的很想理解这一点。

好的,首先我有一个名为Page的类,它简化了一些模板的设置,这是令人讨厌的类:

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提供两个entires(模板只运行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的旧内容?

1 个答案:

答案 0 :(得分:0)

问题是您为Page.__init__函数使用了可变的默认值。请参阅http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments

所以你在每个请求上获得一个新的Page实例,但是重新使用包含你的javascript等的列表/词典。

None替换list / dict默认参数值,检查None中的__init__