объекты или закрытия - когда использовать?

Я могу определить объект и присвоить атрибуты и методы:

class object:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def add(self):
        self.sum = self.a + self.b
    def subtr(self):
        self.fin = self.sum - self.b
    def getpar(self):
        return self.fin

obj = object(2,3)
obj.add()
obj.subtr()
obj.getpar()

или обеспечьте ту же функциональность путем определения закрытия:

def closure(a,b):
    par = {}
    def add():
        par.update({'sum':a+b})
    def subtr():
        par.update({'fin':par['sum']-b})
    def getpar():
        return par['fin']
    return {'add':add,'subtr':subtr,'getpar':getpar}

clos = closure(2,3)
clos['add']()
clos['subtr']()
clos['getpar']()

Я думаю, что объектный синтаксис выглядел бы более чистым к большинству средств просмотра, но является там экземплярами, в которых использование закрытия было бы семантически предпочтительно?

14
задан hatmatrix 5 July 2010 в 23:06
поделиться

4 ответа

В Python замыкания может быть сложнее отлаживать и использовать, чем более обычные объекты (вам нужно где-то сохранять вызываемые объекты, обращаться к ним с тупой нотацией clos ['add' ] и т. Д., ...). Рассмотрим, например, невозможность доступа к сумме , если вы обнаружите что-то странное в результате ... отладка такого рода вещей может быть очень сложной; -)

Единственным реальным компенсирующим преимуществом является простота - но в основном это применимо только к действительно простым случаям (к тому времени, когда у вас есть три вызываемых объекта, которые являются внутренними функциями, я бы сказал, что вы за бортом в этом отношении).

Возможно очень сильная защита (по сравнению с защитой объектов «по соглашению» для объектов классов и экземпляров) или возможная более высокая степень осведомленности программистов Javascript могла бы оправдать использование замыканий, а не классов и экземпляров в крайних случаях, но на практике я не попадал в случаи, когда казалось бы, что такие гипотетические преимущества действительно применимы, поэтому я использую замыкания только в действительно простых случаях ;-).

9
ответ дан 1 December 2019 в 08:42
поделиться

Вы должны использовать ту версию, которая наиболее четко выражает то, чего вы пытаетесь достичь.

В приведенном примере я бы сказал, что версия object более понятна, поскольку, похоже, моделируется объект с изменяющимся состоянием. Если посмотреть на код, который использует значение, то объектная версия, кажется, выражает ясное намерение, в то время как версия закрытия, кажется, имеет операции (индексирование и "волшебные" строки), которые являются второстепенными.

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

def tag_closure(singular, plural):
    def tag_it(n):
        if n == 1:
            return "1 " + singular
        else:
            return str(n) + " " + plural
    return tag_it

t_apple = tag_closure("apple", "apples")
t_cherry = tag_closure("cherry", "cherries");
print t_apple(1), "and", t_cherry(15)

Возможно, это немного понятнее, чем следующее:

class tag_object(object):
    def __init__(self, singular, plural):
        self.singular = singular
        self.plural = plural

    def tag(self, n):
        if n == 1:
            return "1 " + self.singular
        else:
            return str(n) + " " + self.plural

t_apple = tag_object("apple", "apples")
t_cherry = tag_object("cherry", "cherries");
print t_apple.tag(1), "and", t_cherry.tag(15)

В качестве эмпирического правила: если вещь действительно является только одной функцией, и она фиксирует только статическое состояние, то рассмотрите вариант закрытия. Если предполагается, что вещь будет иметь изменяемое состояние, и/или имеет более одной функции, используйте класс.

Другой способ выразить это: Если вы создаете дикту закрытий, вы, по сути, дублируете механизм класса вручную. Лучше доверить это языковой конструкции, предназначенной для этого.

18
ответ дан 1 December 2019 в 08:42
поделиться

Единственная реальная причина, которую я вижу для использования закрытых объектов - это если вы хотите получить довольно сильную гарантию того, что пользователь вашего объекта/закрытого объекта не имеет доступа к скрытой переменной.

Что-то вроде этого:

class Shotgun:
   def __init__(self):
       me = {}
       me['ammo'] = 2
       def shoot():
         if me['ammo']:
           me['ammo'] -= 1
           print "BANG"
         else:
           print "Click ..."
       self.shoot = shoot

s = Shotgun()
s.shoot()
s.shoot()
s.shoot()
3
ответ дан 1 December 2019 в 08:42
поделиться

Синтаксис вызова класса выглядит приятнее, и вы можете создавать подклассы классов. Закрытие также предполагает повторение всех имен, которые вы хотите раскрыть, в операторе return. Возможно, это нормально, если вы хотите иметь действительно приватные методы, которые более скрыты, чем обычное соглашение о префиксе подчеркивания

.
1
ответ дан 1 December 2019 в 08:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: