Python化我:如何在Python中管理调用者上下文变量?
我正在尝试重构一个在Django中比较复杂的视图函数。这个函数里有太多的变量,实在是太庞大了。
理想情况下,我想把这个视图拆分成几个逻辑清晰的小函数。不过,我需要把函数的上下文传递过去,以便能方便地访问这些变量。
举个例子:
def complex_view(request, slug):
some complex logic which creates variable abc ...
...
some more complex logic which uses variable abc ...
...
etc.
应该变成类似这样的:
def complex_view(request, slug):
process_X()
...somehow pass variables and context to next function...
process_Y()
...
etc.
def process_X():
...
def process Y():
...
我能想到几种方法来实现这个,有些方法在这个页面上也提到过: http://mail.python.org/pipermail/tutor/2009-February/067506.html
a. 在主视图中定义子函数。这种方法看起来有点乱,因为很难分清哪些变量是共享的,哪些不是。
b. 将 locals()
作为字典传入。这种方法也有点麻烦,因为现在访问变量有两种方式:xyz
和 contextDict['xyz']
。而且在调用 N
时你得用一种方式,在调用 N+1
时又得用另一种。
c. 强行把所有变量都传给每个函数调用,并返回相关的变量。当变量很多的时候,这种方法会变得非常繁琐。
d. 在C++或C#中,我会简单地创建一个类 MyComplexViewContext
,定义所有共享的变量,并创建成员函数来完成工作。这样在这个类内部就可以用 self.xyz
来访问所有内容。我想我在Python中也可以用这种方法。不过,我不确定这是否是最好的方式。
你觉得在Python/Django中,最好的做法是什么呢?
2 个回答
我建议你可以使用类似于d)的方式,像这样:
class ComplexView_SharedVariables:
# Shared variables (to be used as instance variables, not class variables!)
a = "somevalue"
b = ...
c = ...
class ComplexView_Methods1:
... some functionality ...
class ComplexView_Methods2:
... some more functionality ...
class ComplexView_All(ComplexView_SharedVariables, ComplexView_Methods1, ComplexView_Methods2):
# This class puts together all functionality and shared variables
pass
通过这个方法,你甚至可以把不同的类分到不同的文件里(如果在Django中可以这样做的话,我对Django没有经验)。
我喜欢(d) - 为它创建一个类,然后用类里的函数来完成工作。
在Django中,视图其实就是一个可以被调用的东西,它接受一个HTTP请求对象,还有你在URL路由中传给它的其他参数。
如果你在Python类里定义一个__call__
方法,那么这个类就可以像函数一样被调用,像这样:
class MyView(object):
def __call__(self, request, slug)
# do stuff here
def helper_method(self):
# etc.
然后你可以在你的urls.py
文件中用类名来引用它,它就会像其他Python函数一样被调用。
这样做还可以让你把相似的视图变成对象实例:
class MyView(object):
def __init__(self, parameters):
# initialize instance
def __call__(self, request, slug):
# main view code goes here
first_view = MyView("some parameter")
second_view = MyView("some other parameter") # creates second object instance
在urls.py中,你可以引用这些对象(而不是类)——这些对象也可以像函数一样被调用。
其他的小技巧是使用继承来定义相似的视图,或者在一个基类中提供一些通用功能,让专门的视图类去继承这个基类。
你可以查看Simon Willison的这个幻灯片获取更多细节,或者看看这个示例代码来了解具体的例子。