Pythonize Me: как управлять переменными контекста вызывающей стороны в Python? (Python / Django) - PullRequest
4 голосов
/ 12 января 2010

Я пытаюсь реорганизовать довольно здоровенную функцию просмотра в 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 ]

10 голосов
/ 12 января 2010

Мне нравится (d) - создайте для него класс и используйте функции-члены для выполнения работы.

В Django представление является просто «вызываемым», которое принимает объект HTTPRequest, и любые другие параметры, передаваемые ему в 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 ссылаться на объекты (а не на класс) - объекты также можно вызывать как функции.

Другие приемы - использовать наследование для определения сходных представлений или предоставить некоторые общие функциональные возможности для ряда сходных представлений в базовом классе, которые затем наследуют специализированные классы представлений.

Вы можете посмотреть это слайд-шоу Саймона Уиллисона для получения более подробной информации или этот фрагмент для конкретного примера

0 голосов
/ 12 января 2010

Могу ли я предложить использовать что-то похожее на 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, у меня нет опыта работы с ним).

...