Наследяване на Django CBV: Заменящи атрибути

Създавам персонализирани изгледи, базирани на класове, за проект на Django и се сблъсках с дизайнерско решение относно атрибути.

Getter функции

Разгледах общите изгледи на Django и видях, че има доста класове, които предоставят както променливи на класа, така и персонализирани функции за получаване. напр..

class FormMixin(object):
    initial = {}
    def get_initial(self):
        return self.initial

Това дизайнерско решение има смисъл, тъй като по този начин можете да извикате super() в метод за отмяна на разширяващ се клас.

Имоти

В моя проект има определени стойности, които понякога бих могъл да отменя с проста стойност, но понякога трябва да се генерират на ден. Първоначално създадох методи, подобни на горните, но след това си помислих, че може би свойствата са по-добър начин да направя това.

class MyBaseView(OtherView):
    counter = None

class MyExtendingView(MyBaseView):
    counter = 5

class MyOtherExtendingView(MyBaseView):
    @property
    def counter(self):
        return self.other_function()

инстанция.__dict__

Смятам да използвам тези стойности в шаблон. Предавам екземпляри на разширяващите се изгледи към шаблон и показвам атрибутите по следния начин:

context['class_instances'] = [MyExtendingView(), MyOtherExtendingView()]

{% for instance in class_instances %}
    {{ instance.counter|default:'' }}
{% endfor %}

Сега, тъй като това е шаблон и няма особено значение дали атрибутът на екземпляра е стойност или функция, бих могъл също да напиша моите класове така:

class MyExtendingView(MyBaseView):
    counter = 5

class MyOtherExtendingView(MyBaseView):
    def counter(self):
        return self.other_function()

def counter ще замени стария базиран на стойност атрибут в instance.__dict__.

Въпрос

За да стигнем до въпроса, кой от изброените подходи е най-добрият избор?

  • Подходът на getter е хубав, тъй като позволява super()-извикване на функцията getter на родителя, но в повечето от моите случаи това вероятно никога няма да е необходимо.
  • Подходът на свойствата е много по-прост и води до писане на по-малко код. Въпреки това не мога да super()-извикам функцията за собственост на родител. В повечето случаи няма да имам нужда от това поведение, но може да има случаи, в които имам нужда от super() функционалност, така че ще има комбинация от прости атрибути, които могат да бъдат заменени с помощта на свойства и персонализирани функции за получаване.
  • Последният подход е дори по-малко код от подхода на свойствата, но се съмнявам, че е добър стил.

person Danilo Bargen    schedule 29.02.2012    source източник


Отговори (1)


Подходът на свойствата е много по-прост и води до писане на по-малко код. Въпреки това не мога да извикам функцията за свойство на родител.

Всъщност можете да получите достъп до родителските свойства чрез super():

class A(object):
    @property
    def prop(self):
        return 'A.prop'

class B(A):
    @property
    def prop(self):
        return '%s - %s' % (super(B, self).prop, 'B.prop')

>>> b = B()
>>> b.prop
'A.prop - B.prop'
person Jakub Roztocil    schedule 29.02.2012
comment
А, как го пропуснах? :) Значи смятате, че свойствата са по-добри от персонализираните методи? Знаете ли или подозирате нещо за дизайнерското решение на екипа на Django? - person Danilo Bargen; 01.03.2012
comment
Бих казал, че са избрали методи пред свойства, защото се очаква тази част от рамката да бъде презаписвана много често и явното е по-добро от неявното. - person Jakub Roztocil; 01.03.2012
comment
Що се отнася до свойствата срещу методите като цяло: зависи :) Обикновено започвам с обикновени атрибути и ги променям в @property-s, когато е необходимо някакво динамично поведение (също описано тук: blaag.haard.se/What-s-the-point-of-properties-in-Python). Предпочитам методи, когато се очаква отмяна, защото може да не винаги е очевидно, че нещо, което изглежда като атрибут, всъщност е резултат от няколко извиквания на метод във веригата на наследяване. - person Jakub Roztocil; 01.03.2012
comment
Добре, това за explicit is better than implicit има смисъл. Особено, когато функциите правят нещо повече от просто получаване (напр. промяна на self). Но мисля, че предпочитам простите свойства на getter пред експлицитните функции, тъй като те са по-сбити и по-СУХИ (няма get_foo, което не прави нищо освен връщането на self.foo). - person Danilo Bargen; 02.03.2012