Протестируйте контракт интерфейса модуля, который Вы тестируете:
клиентом я имею в виду код, которые используют Ваш класс.
ожидаемым поведением я имею в виду ожидаемый результат метода на возвращаемых значениях и объектных состояниях.
И фокус Ваши тесты на логика (если, поскольку, в то время как, и т.д.), потому что плоский материал как свойства имеет меньшие возможности сбоя, не будучи пойманным нормальной эксплуатацией Вашего приложения.
Я предпочитаю использовать подписанный, если только не знаю, что мне нужен беззнаковый, поскольку int
обычно подписан, и это требует больше усилий. ввести unsigned int
, а uint
может вызвать у другого программиста небольшую паузу, чтобы подумать о том, какими могут быть значения.
Итак, я не вижу никакой пользы в простом использовании значений по умолчанию. в беззнаковое, так как нормальное int подписано.
и присваивания, такие как xb = 2
, на языках, которые имеют свойства (набор языков, который включает, но не ограничивается Python), точно такие же, как для методов получения и установки в, например, Java: те же ожидания, то же отсутствие гарантий, обеспечиваемых языком.
Первая победа для свойств - это синтаксис и удобочитаемость. Необходимость писать, например,
x.setB(x.getB() + 1)
вместо очевидного
x.b += 1
взывает о мести богам. В языках, поддерживающих свойства, нет абсолютно никакой веской причины заставлять пользователей класса проходить через круговорот такого византийского шаблона, влияя на читабельность их кода без каких-либо преимуществ.
В частности, в Python есть еще один большой плюс для использование свойств (или других дескрипторов) вместо геттеров и сеттеров: помимо влияния на читаемость кода ваших пользователей, вы также беспричинно тратите машинные циклы (и энергию, которая идет на их компьютер во время этих циклов ;-), снова без уважительной причины
Ваш единственный аргумент против свойств - это, например, то, что «внешний пользователь обычно не ожидает никаких побочных эффектов в результате присваивания»; но вы упускаете тот факт, что один и тот же пользователь (на таком языке, как Java, где геттеры и сеттеры широко распространены) не ожидал бы (наблюдаемых) «побочных эффектов» в результате вызова сеттера (и тем более для геттера ;-). Это разумные ожидания, и вы, как автор класса, должны попытаться учесть их - независимо от того, используются ли ваши сеттер и получатель напрямую или через свойство, не имеет значения. Если у вас есть методы с важными наблюдаемыми побочными эффектами, не не назовите их getThis
, setThat
и не используйте их через свойства.
Жалоба на то, что свойства "скрыть реализацию" совершенно неоправданно: большая часть всего ООП связана с реализацией сокрытия информации - возложением на класс ответственности за представление логического интерфейса внешнему миру и его внутренней реализации, насколько это возможно. Геттеры и сеттеры, как и свойства, являются инструментами для достижения этой цели. Свойства просто справляются с этим лучше (на языках, которые их поддерживают; -).
Жалоба на то, что свойства «скрывают реализацию», совершенно неоправданна: большая часть всего ООП связана с реализацией сокрытия информации - возлагая на класс ответственность за представление логического интерфейса внешнему миру и его внутреннюю реализацию. как можно лучше. Геттеры и сеттеры, как и свойства, являются инструментами для достижения этой цели. Свойства просто справляются с этим лучше (на языках, которые их поддерживают; -).
Жалоба на то, что свойства «скрывают реализацию», совершенно неоправданна: большая часть всего ООП связана с реализацией сокрытия информации - возлагая на класс ответственность за представление логического интерфейса внешнему миру и его внутреннюю реализацию. как можно лучше. Геттеры и сеттеры, как и свойства, являются инструментами для достижения этой цели. Свойства просто справляются с этим лучше (на языках, которые их поддерживают; -).
Идея состоит в том, чтобы позволить вам избежать необходимости писать геттеры и сеттеры до тех пор, пока они вам действительно не понадобятся.
Итак, для начала вы напишите:
class MyClass(object):
def __init__(self):
self.myval = 4
Очевидно, теперь вы можете написать myobj.myval = 5
.
Но позже вы решаете, что вам действительно нужен сеттер, так как одновременно вы хотите сделать что-то умное. Но вы не хотите изменять весь код, который использует ваш класс - поэтому вы обернули сеттер в декоратор @property
, и все просто заработало.
, но скрывая тот факт, что ab = 2 не является простое задание похоже на рецепт для неприятностей
Но вы этого не скрываете; этого факта никогда не было. Это питон - язык высокого уровня; не сборка. Некоторые из «простых» утверждений в нем сводятся к инструкциям для одного процессора. Вносить простоту в задание - значит читать вещи, которых там нет.
Когда вы говорите xb = c, вы, вероятно, должны думать только о том, что «что бы ни случилось, теперь xb должно быть c».
Основная причина в том, что он действительно выглядит лучше. Он более питонический. Специально для библиотек. something.getValue () выглядит менее привлекательно, чем something.value
В plone (довольно большая CMS) у вас был document.setTitle (), который выполняет много вещей, таких как сохранение значения, его повторная индексация и т.д. Просто сделать document.title = 'something' лучше. Вы знаете, что в любом случае многое происходит за кулисами.
Вот мой старый пример. Я обернул библиотеку C, в которой были такие функции, как «void dt_setcharge (int atom_handle, int new_charge)» и «int dt_getcharge (int atom_handle)». Я хотел на уровне Python сделать "atom.charge = atom.charge + 1".
Декоратор "property" упрощает это. Что-то вроде:
class Atom(object):
def __init__(self, handle):
self.handle = handle
def _get_charge(self):
return dt_getcharge(self.handle)
def _set_charge(self, charge):
dt_setcharge(self.handle, charge)
charge = property(_get_charge, _set_charge)
10 лет назад, когда я писал этот пакет, мне пришлось использовать __getattr__ и __setattr__, которые сделали это возможным, но реализация была намного более подвержена ошибкам.
class Atom:
def __init__(self, handle):
self.handle = handle
def __getattr__(self, name):
if name == "charge":
return dt_getcharge(self.handle)
raise AttributeError(name)
def __setattr__(self, name, value):
if name == "charge":
dt_setcharge(self.handle, value)
else:
self.__dict__[name] = value
Вы правы, это просто синтаксический сахар. Может случиться так, что в зависимости от вашего определения проблемного кода нет хороших применений.
Учтите, что у вас есть класс Foo, который широко используется в вашем приложении. Теперь это приложение стало довольно большим, и далее можно сказать, что это веб-приложение, которое стало очень популярным.
Вы определили, что Foo является узким местом. Возможно, можно добавить в Foo кеширование, чтобы ускорить его. Использование свойств позволит вам сделать это без изменения какого-либо кода или тестов вне Foo.
Да, конечно, это проблемный код, но вы просто сэкономили много $$, быстро исправив его.
Что делать, если Foo находится в библиотеке, которой у вас сотни или тысячи пользователей? Что ж, вы избавили себя от необходимости посоветовать им провести дорогостоящий рефакторинг при обновлении до последней версии Foo.
В примечаниях к выпуску есть строка о Foo вместо абзаца руководства по переносу.
Опытные программисты Python этого не делают. ожидают многого от ab = 2
, кроме ab == 2
, но они знают, что даже это может быть неправдой. То, что происходит внутри класса, - это его личное дело.
ab = 2
, кроме ab == 2
, но они знают, что даже это может быть неправдой. То, что происходит внутри класса, - это его личное дело. Не ожидают многого от ab = 2
, кроме ab == 2
, но они знают, что даже это может быть неправдой. То, что происходит внутри класса, - это его личное дело.