Python化我:如何在Python中管理调用者上下文变量?

4 投票
2 回答
1586 浏览
提问于 2025-04-15 17:54

我正在尝试重构一个在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() 作为字典传入。这种方法也有点麻烦,因为现在访问变量有两种方式:xyzcontextDict['xyz']。而且在调用 N 时你得用一种方式,在调用 N+1 时又得用另一种。

c. 强行把所有变量都传给每个函数调用,并返回相关的变量。当变量很多的时候,这种方法会变得非常繁琐。

d. 在C++或C#中,我会简单地创建一个类 MyComplexViewContext,定义所有共享的变量,并创建成员函数来完成工作。这样在这个类内部就可以用 self.xyz 来访问所有内容。我想我在Python中也可以用这种方法。不过,我不确定这是否是最好的方式。

你觉得在Python/Django中,最好的做法是什么呢?

2 个回答

0

我建议你可以使用类似于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没有经验)。

10

我喜欢(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的这个幻灯片获取更多细节,或者看看这个示例代码来了解具体的例子。

撰写回答