Найти - Пользователи
Полная версия: Что можно написать на Python?
Начало » Флейм » Что можно написать на Python?
1 2 3 4 5
balu
Андрей Светлов
все равно требуется постоянно следить за архитектурой и писать тесты. Не делаешь этого - копаешь себе яму. Особенно если разработчиков много.
да. Но не всегда можно предугадать все варианты типов, которые могут быть переданы в реальной работе. Впрочем, тогда и в строготипизированных ЯП возникнет ругань.
shiza
Я для интерфейсов делаю классы-хранилища с проверкой типов.
Ferroman
У меня такой потребности не возникало, но интересно - как делаете строгую типизацию где надо? Небольшой пример бы, для иллюстрации.
Спасибо.
shiza
Я для себя использую примерно такой вариант. Знаю, что он не идеален, но мне пока хватает.
# -*- coding: UTF-8 -*-

class BaseIface(object):
'''
базовый класс, с проверкой имени кладомой в него переменной и ее типа
'''
def __setattr__(self, name, value):
if not name in self.right_vars: #проверяем, что такое имя разрешено
raise ValueError, ('bad variable name')
elif not isinstance(value, self.right_vars[name]): #поверяем, что такой тип разрешен
raise ValueError, ('bad variable type')
else:
object.__setattr__(self, name, value) #если все ок - кладем =)


class PriceField(BaseIface):
'''
интерфейсный класс
'''
right_vars = { #список разрешенных переменных с указанием их типов.
'price': float,
'name': unicode
}


class PriceFieldDef(BaseIface):
'''
другой интерфейсный класс
'''
right_vars = { #список разрешенных переменных с указанием их типов.
'price': float,
'name': unicode
}

#можно забить значение по умолчанию
def __init__(self):
self.price = 0.0
self.name = u''


f = PriceField()

f.price = 3.0
f.name = u'test'

f1 = PriceFieldDef()
print f1.price

#f.price = 1 #ошибка
#f.prise = 1.0 #ошибка
Использую это для обмена даными между разными блоками программы =)
Андрей Светлов
Типизированные атрибуты
>>> class typed_attr(object):
... def __init__(self, name, type):
... self.name = name
... self.type = type
... def __set__(self, inst, value):
... assert isinstance(value, self.type)
... setattr(inst, '_typed_'+self.name, value)
... def __get__(self, inst, owner):
... assert inst is not None
... return getattr(inst, '_typed_'+self.name)
...
>>> class A(object):
... a = typed_attr('a', int)
...
>>> a = A()
>>> a.a = 34
>>> a.a
34
>>> a.a = 'abc'
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "<interactive input>", line 6, in __set__
AssertionError
>>>
При использовании peak.decorators можно избежать самоцитирования при создании свойства и вычислять имя атрибута после создания дескриптора. Того же эффекта можно добиться создав метакласс для всех пользовательских типов. Но это уже детали.

Для проверки аргументов/вычисляемого значения подойдут тривиальные декораторы. Можно их сделать очень быстрыми (снижаем накладные расходы на обвязку), при этом возможная сложность декораторов мало волнует - весь люд воспринимает их как “магию”. Примерно так же мало кто задумывается, как именно реализованы некоторые нетривиальные питоновские builtins и itertools. Дока есть - и ладно.
Очень хочу порекомендовать статью Сергея Щетинина, посвященную как раз этому.

P.S. Да, всем этим стоит заниматься исключительно в публичных интерфейсах. Интимные детали подсистем в проверке типов н нуждаются. Требуется именно защита от дурака (программиста из другого отдела), который всего лишь хочет быстро вызывать вашу API и не вникать в детали реализации. Если API очень прост и не допускает разночтений - опять же проверку типов опускаем за ненадобностью. У нас она “отключена по умолчанию” - ничего лишнего. Но когда часто начинаем “спотыкаться” или просто чувствуем “проблемное место” - вводим.
shiza
Андрей Светлов
Интимные детали подсистем в проверке типов н нуждаются. Требуется именно защита от дурака (программиста из другого отдела), который всего лишь хочет быстро вызывать вашу API и не вникать в детали реализации.
Поддреживаю.
Андрей Светлов
Если API очень прост и не допускает разночтений - опять же проверку типов опускаем за ненадобностью.
Не совсем согласен, иногда бывают глупые опечатки, от которых спасет такая проверка.
Ferroman
Спасибо, весьма интересно.
Андрей Светлов
Еще не могу удержаться:
- хорошая система исключений.
- Во первых, информативный текст. В примере я бросал простой assert. По хорошему нужно приложить к нему второй параметр. Что-то вроде
assert isinstance(value, self.type), ‘Attribute %r must be instance of %r type, got %r’%(self.name, setlf.type, type(value))
Очень облегчает анализ ошибки
- Во вторых, никогда не ловите и не бросайте Exception. except Exception съест в том числе и непредвиденные ошибки - NameError например. Если не знаете тип исключения - RuntimeError был сделан как раз для вас.
- Если ловите, скажем, ValidationError на save и хотите превратить его в TransactionError - сделайте так, чтобы ваш TransactionError мог рассказать о вложенном исключении, которое это проблему вызвало. Вложеные тип, значение и, главное, stack trace. Опять же поможет.
- логирование.
- Модуль logging хорошо - всегда его используйте. Имейте много логеров. Год назад накропал статейку Пользуюсь практически без изменений - разве что по рекомендации Макса Ищенко добавил mod_logger. В девелоперской конфигурации обязательно логируйте помимо всего прочего на консоль. В production - обязательно в файл. Его вам хотя бы по email перешлют. Файлы ротировать и сохранять достаточно долгое время. Чтобы на тот момент, когда вам клиент нажалуется - у него логи все еще были.
- принты не используйте. Сам их часто вставляю - но только для отладки. В svn они не попадают. Хотели даже pre-commit hook вставить, который питоновские файлы бы парсил и если увидел незакомментареный print - commit бы не допускал. Руки не доходят, по простому незлым тихим словом поддерживаем порядок.
- repr. Очень полезная штука. Практически у каждого класса должен быть свой переопределенный __repr__. Который нормально описывает класс. Например, для пресловутого объекта из БД по имени “пользователь” возвращается строка <User ‘vpupkin@gmai.com’> если email - уникальный индекс. Опять же сокращает отладку. Обратите внимание, что email в кавычках - стандартная реализация repr для строки. Позволяет наглядно показать, есть ли в параметре пробелы или таки нет. Тоже сохраняет время. repr вызывается при ‘%r’%arg, а при ‘%s’%arg зовется str - который может иметь (и зачастую так и есть) совершенно другую реализацию. При логировани и бросании исключений используйте именно repr. Экономит время, особенно когда паренек из support team подходит с вопросом - а почему у клиента не работает. У этого паренька иногда тоже воспроизводится - если он на том же environment смог поймать проблему. Но нет отладчика. Исходников по умолчанию тоже нет. Перенастроить мое девелоперское окружение на то, что вертится у заказчика - пара часов работы в лучшем случае. В худшем - сутки (и это при том, что заказчики сидят в своем интранет, к которому мы имеем достаточно свободный доступ - просто чудеса). Зато есть логи. Чем они информативней (молчат о стандартных ситуациях и подробно рассказывают о возникшей проблеме - тем быстрее она решается)

- это позволяет свести отладку к минимуму. Да, я сам тоже ей пользуюсь. import pdb;pdb.set_trace() Получаю вполне приличную питоновскую консоль в проблемном месте. Все, что я прошу у системы - информативное (помните про repr). Отлаживать долго не нужно. Чаще нужно именно войти питоном куда следует и поспрашивать. Стек, окружение, то-се. Не нужно трассировать глубокие стеки вызовов - логи скажут. После вырабатывания привычки к подобному стилю здорово экономишь свое время. Как и привычка к написанию юниттестов спасает от часов тупой отладки.

- Ключевое слово - привычка. Привык, и пишу мало кода, который делает много дела. Привык - и затягиваю сдачу истории до тех пор, пока она не будет готова с моей точки зрения. В результате разработка получается сбалансированной и быстрой.
Привык - и выдаю всегда только хороший (по крайней мере с моей точки зрения) код.

P.S. Конечно, все вышесказанное - только лишь моя точка зрения. Каждый может не согласиться, оспорить или противопоставить свою. С удовольствием выслушаю.

balu
Спасибо за роль хорошего оппонента. Ответы на твои вопросы помогли взглянуть на проблему немного с другой стороны.
Ferroman
Это хорошо, что ты не сдержался :)
PooH
Ferroman
Это хорошо, что ты не сдержался :)
+1 очень интересно!!!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB