Тип безопасности в Python

Я определилVector класс с тремя переменными свойства:x, y а такжеz, Координаты должны быть действительными числами, но ничто не мешает сделать следующее:

>>> v = Vector(8, 7.3, -1)
>>> v.x = "foo"
>>> v.x
"foo"

Я мог бы реализовать «безопасность типов» следующим образом:

import numbers

class Vector:
    def __init__(self, x, y, z):
        self.setposition(x, y, z)

    def setposition(self, x, y, z):
        for i in (x, y, z):
            if not isinstance(i, numbers.Real):
                raise TypeError("Real coordinates only")

        self.__x = x
        self.__y = y
        self.__z = z

    @property
    def x(self):
        return self.__x

    @property
    def y(self):
        return self.__y

    @property
    def z(self):
        return self.__z

... но это кажется непифоническим.

Предложения?

 BlueSky14 янв. 2017 г., 11:59
Я понимаю, что такого рода проблемы обычно возникают с большими проектами / командой. Если безопасность типов - это то, к чему вы сильно относитесь, я предлагаю вам вместо этого взглянуть на scala.
 S.Lott20 сент. 2010 г., 16:07
Но почему? Целые числа полностью работают.

Ответы на вопрос(5)

кто-то может сознательно взломать ваш код, предоставив значения, для которых ваш контейнер не будет работать, но это точно так же с другими языками. И даже если кто-то поместит правильное значение параметра в метод или функцию-член, это не обязательно означает, что он не сломан: если программа ожидает IP-адрес, но вы передаете имя хоста, он все равно не будет работать, хотя оба могут строки.

То, что я говорю: мышление Python по своей сути отличается. Типизирование утки в основном говорит: Эй, я не ограничен определенными типами, но интерфейсом или поведением объектов. Если объект действует так, как будто я ожидал этого, мне все равно - просто сделайте это.

Если вы пытаетесь ввести проверку типов, вы в основном ограничиваете одну из самых полезных функций языка.

Тем не менее, вам действительно нужно углубиться в разработку через тестирование или, по крайней мере, в модульное тестирование. На самом деле нет оправдания тому, чтобы не делать это с динамическими языками - это просто перенос способа обнаружения ошибок (типа) на другой этап процесса сборки, от времени компиляции к запуску набора тестов несколько раз в день. Хотя это кажется дополнительным усилием, на самом деле это сократит время, затрачиваемое на отладку и исправление кода, поскольку это по своей сути более мощный способ обнаружения ошибок в вашем коде.

Но хватит этого, я уже болтаю.

 Jon Coombs15 мар. 2014 г., 07:36
Модульные тесты хороши, но пошаговые тесты в отладчике - не самый оптимальный способ узнать, каких уток ожидает прохождение каждого метода, то есть как правильно использовать API. И трудно гарантировать, что ваш модульный тест всегда будет охватывать каждый крайний случай.
 Jon Coombs15 мар. 2014 г., 07:35
Хотя «интерфейс» здесь немного неправильный, потому что ни один интерфейс явно не определен (за исключением, надеюсь, в комментариях). Утиная печать означает, что вы на самом деле просматриваете или запускаете код, чтобы увидеть, что такое «интерфейс». По моему (ограниченному) опыту работы с Python, это самый большой недостаток утиной печати. Написание собственного кода быстрее, но использование чужого недокументированного API (например, написание плагина) намного сложнее, поэтому комментарии становятся более важными.

Я считаю, что пытаться помешать кому-то сделать что-то подобное - непифоника. Если вы должны, то вы должны проверить безопасность типовв течение любые операции, которые вы можете сделать, используяVector, по-моему.

Цитирую Г.В.Р:

мы все взрослые.

в конце концов. Видеть этовопрос и его ответы для получения дополнительной информации.

Я уверен, что более опытные Pythonistas здесь могут дать вам лучшие ответы.

Утка набрав это обычный способ в Python. Это должно работать со всем, чтоведет себя как число, но не обязательноявляется реальное число.

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

что нет смысла проверять тип здесь. Кроме того, ваш класс не будет очень быстрым, если он написан на чистом Python.

Если вы хотите более питонное решение - вы можете использовать установщики свойств, такие как:

@x.setter
def x(self, value):
    assert isinstance(value, numbers.Real)
    self.__x = value

Оператор assert будет удален, когда вы отключите отладку или включите режим оптимизации.

В качестве альтернативы, вы можете заставитьvalue с плавающей точкой в ​​сеттере. Это вызовет исключение, если тип / значение не конвертируемо:

@x.setter
def x(self, value):
    self.__x = float(value)
Решение Вопроса

почему вы хотите проверить тип при установке этих значений. Просто поднятьTypeError в любом расчете, который случайно наткнулся на неправильныйзначение тип. Бонус: стандартные операции уже делают это.

>>> 3.0 / 'abc'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for /: 'float' and 'str'
 knitti15 мар. 2014 г., 22:53
Я думаю, что вопрос был о LBYL против EAFP, поэтому в «питоническом» смысле имеет смысл не только «разрешать» типы, которые вы изначально намеревались. Для «известного плохого» результата имеет смысл сократить путь выполнения (рейз).
 Jon Coombs15 мар. 2014 г., 07:39
А затем напишите исчерпывающий набор модульных тестов, которые выполняют все ветви вашего кода, чтобы отследить ваши ошибки TypeErrors, прежде чем ваши пользователи это сделают. Правильно? В любом случае, относительно того, когда следует выдать ошибку: если вы знаете, что определенная комбинация недействительна и вызовет проблемы, разве не было бы лучше / яснее потерпеть неудачу как можно раньше? Разве неудача на ранней стадии не делает поиск корня намного проще? (Я полагаю, что «почему он недействителен» менее понятно.)

Ваш ответ на вопрос