Утиная машинка: как бы ты отнесся к этой ситуации? - PullRequest
1 голос
/ 10 ноября 2009

Относительно новый для Python. Недавно я опубликовал вопрос, касающийся проверки того, что тип данных является логическим. [ Использовать дескриптор (РЕДАКТИРОВАТЬ: не один декоратор) для нескольких атрибутов?

В ответах дана ссылка на утку. У меня есть простой пример, и я хочу убедиться, что понимаю. Если мой код:

class Foo4(object):
    def __init__(self):
        self.bool1=True

    def send_rocket(self, bool_value):
        if not bool_value:
            print "Send rocket ship to sun first... bad move."
         print "Send rocket ship to Mars... good move."

f=Foo4()
f.send_rocket(f.bool1) 
#Send rocket ship to Mars... good move.

f.bool1=None
f.send_rocket(f.bool1) 
#Send rocket ship to sun first... bad move.
#Send rocket ship to Mars... good move.

Если я правильно понимаю тип утки, в приведенном выше классе я верю , что bool1 всегда будет логическим значением: мне не нужно проверять, является ли bool1 == False или bool1 == True. Когда кто-то использует мой модуль неправильно, то есть bool1 = None, метод выдает то, чего я не хотел бы выполнить без указания на то, что возникла проблема ... и люди на ракетном корабле умирают.

Другой способ, которым я мог бы написать код, чтобы гарантировать, что bool1 всегда является истинным логическим значением (кредиты для BooleanDescriptor в ссылке выше!):

class BooleanDescriptor(object):
    def __init__(self, attr):
        self.attr = attr

    def __get__(self, instance, owner):
        return getattr(instance, self.attr)

    def __set__(self, instance, value):
        if value in (True, False):
            return setattr(instance, self.attr, value)
        else:
            raise TypeError

class Foo4(object):
    def __init__(self):
        self._bool1=True
    bool1 = BooleanDescriptor('_bool1')

    def send_rocket(self, bool_value):
        if not bool_value:
            print "Send rocket ship to sun... bad move."
        print "Send rocket ship to Mars... good move."

f=Foo4()
f.send_rocket(f.bool1)
#Send rocket ship to Mars... good move.

f.bool1=None
#TypeError.
#Never gets here: f.send_rocket(f.bool1)

Я понимаю, что первый путь (не проверка) - это правильный путь? Я имею в виду, я всегда мог написать код явно в первом примере как:

    if bool_value ==True:
        print "do something"
    elif bool_value == False:
        print "do something else"
    else:
        print "invalid boolean value"

Но если я делаю это в каждом методе и так далее, где я использую bool1, почему, черт возьми, я бы просто не подтвердил, что bool1 был истинным логическим значением в первую очередь (DRY!)!?!? : -)

Спасибо!

Пол

Ответы [ 2 ]

2 голосов
/ 10 ноября 2009

Обычный стиль Python - первый подход.

Например, я могу захотеть использовать вашу библиотеку с чем-то, что не может решить, идти ли на солнце или на Марс до самого последнего момента. Так что я мог бы передать экземпляр этого класса:

class LastMinuteDecision(object):

    def __bool__(self):
        return make_decision_now()

Если бы вы поместили там несколько тестов, думая, что вы лучше меня знаете, как я буду называть вашу библиотеку, то я не смог бы этого сделать, и я был бы очень раздражен и, вероятно, сказал бы вам прекратить писать Java ( или что угодно) в Python ...

[edit: в случае, если неясно, метод __bool__ делает экземпляр «похожим» »на логический. Он вызывается, когда язык ожидает логическое значение.]

Вы можете подумать, что это безумие, но оно работает на удивление хорошо.

0 голосов
/ 10 ноября 2009

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

Я не эксперт, но я ожидаю, что ваш последний метод является лучшим (то есть проверьте true, false или другое).

...