Python 方法中的变量和对象创建
我知道在Python中,方法里声明的变量在外面是看不见的。那么这些变量的生命周期是怎样的呢?我觉得每次调用这个方法的时候,里面声明的变量应该都是新创建的。
我之所以问这个,是因为我遇到了以下情况。我有一个方法,下面是我用的自定义Filter类(这个是用在cherrypy里的,可能不太相关,但我还是加上,以防有什么影响)。
首先是我使用的自定义Filter类:
class Filter():
"""
Class used to filter tables displayed in UI, based on few criteria.
Initialize filter with a list of fields, and correspondinf values.
"""
def __init__(self, display_name= "", fields= [], values= [], operations= []):
self.display_name = display_name
self.fields = fields
self.values = values
self.selected = False
self.operations = operations
接下来是我想说的方法:
@cherrypy.expose
@logged()
def getfiltereddatatypes(self, name, filters, datatype):
...some mumbo jumbo...
default_filter = self._get_default_filters(inputTree, name)
#default_filter here can be a object of type Filter if defined or None otherwise
print "RECIEVED " + str(filters)
if default_filter is not None:
print "CREATING NEW"
new_filter = copy.deepcopy(default_filter)
else:
print "CREATING NEW"
new_filter = Filter()
[new_filter.fields.append(value) for value in filters['fields']]
[new_filter.operations.append(value) for value in filters['operations']]
[new_filter.values.append(value) for value in filters['values']]
print "LENGTH =" + str(len(new_filter.fields))
...Some other mumbo jumbo....
简单来说,我想把作为参数传入的过滤器值添加到filters
变量里的默认值中。但我希望每次调用这个方法的时候都能这样做。为了更好地解释这个问题,我加了打印语句。第一次调用方法时:
RECIEVED {'operations': ['!='], 'fields': ['model.DataType.subject'], 'values': ['w']}
CREATING NEW
LENGTH =1
如预期的那样,创建了一个新的Filter对象,并且从接收到的参数中添加了操作、字段和数值,length(fields)
= 1。但是在第二次调用时:
RECIEVED {'operations': ['!='], 'fields': ['model.DataType.subject'], 'values': ['']}
CREATING NEW
LENGTH =2
这个行为我就无法解释了。正如你所看到的,if语句中的CREATING NEW分支又被调用了,filters
变量里是一个包含一个项目的列表,但结果的长度却是2。如果我不断运行它,结果会一直增加。就好像new_filter = Filter()
这个调用返回的是上一次方法调用的new_filter
。是什么导致了这种行为呢?我在想,也许如果我用new_filter = copy.deepcopy(Filter())
,可能会解决这个问题,但为什么我必须这样做呢?
祝好,
Bogdan
1 个回答
def __init__(self, display_name= "", fields= [], values= [], operations= [])
这些列表只会创建一次。所以如果你修改了它们,下次调用的时候就会得到修改后的列表。如果你不想要这种行为,只需把默认值设置为 None
,然后加上类似下面的代码:
if fields is None:
fields = []
self.fields = fields
另一种解决办法是无论传入什么,都创建一个新的列表:
self.fields = list(fields)
关于这种行为,还有一篇详细的文章,可以在这里查看:http://effbot.org/zone/default-values.htm
顺便说一下,你对列表推导式的使用不太恰当。
[new_filter.fields.append(value) for value in filters['fields']]
应该是
new_filter.fields += filters['fields']