Архив метки: 3.x

Django 1.5 и Python 3 (Перевод)

Django 1.5 уже «полностью» поддерживает Python 3, как минимум с технической точки зрения. Поддержка реализована, проверена и работает. Я планирую поместить свой сайт на Django 1.5 / Python 3.3 уже в этом году. Так что в этом смысле всё «готово».
Однако, это не значит, что я рекомендую делать это другим.
У мы даём серьёзные обещания обратной совместимости и мы ещё не на 100% хорошо соответствуем Python 3 API. Есть маленькая (не нулевая) вероятность, что надо будет что-то изменить между 1.5 и 1.6; и мы бы хотели сохранить возможность обратной несовместимости (для Python 3).
Кроме того, есть маленькая (но, опять же, не нулевая) вероятность что есть 1-3 серьёзрых бага в поддержке Python 3 и мы не хотим, чтобы люди с этим столкнулись.
Наконец, значительная часть «хорошести» Django — сторонние приложения, многие из которых не поддерживают ещё Python 3. И это серьёзная проблема для Django / Py3, так как многие сайты используют большое количество сторонних приложений. Так что перед переходом на Python 3 Вы должны решить для себя вопрос: «Готов ли я отказаться от этого приложения или готов портировать его на Python 3 и внести патч?»
В случае моего сайта я к этому готов. Я достаточно хорошо знаю Django, чтобы не бояться потенциальных багов и обратной несовместимости и я могу заняться патчами для Python 3.
Но к большинству пользователей это не относится, так что я надеюсь, что большая часть пользователей Django дождётся 1.6 перед тем, как начать использовать Python 3.
У нас пока нет твёрдых сроков. Я думаю, что 1.6 можно ждать где-то через 6-9 месяцев, но это зависит от слишком многих факторов. Реально срок может быть и год и 3-4 месяца. Увидим 🙂

Автор: Ishayahu Lastov

Хватит использовать “print” для отладки: пятиминутное введение в модуль logging Python’а (Перевод)

  • Это руководство короткое
  • Для поиска ошибок в коде Вы можете использовать print для просмотра значений переменных
  • НЕ делайте этого. Используйте модуль logging
Модуль logging предпочтительнее, так как:
  • Легко можно поместить указатель времени в каждое сообщение
  • Вы можете использовать разные уровни срочности ваших сообщений и фильтровать их по этому уровню
  • Когда Вы захотите позже найти / изменить лог-сообщения Вы не перепутаете их с другим выводом команды print
  • Если Вы хотите вывести лог в файл, то очень легко будет игнорировать вывод лог-сообщений
Использование pirnt подходит для тех программистов, у которых достаточно времени. Но лучше использовать logging. Кроме того, научитесь использовать отладчик Python для отладки ошибок и Pylint для предотвращения появления ошибок и для того, чтобы сделать код более читаемым.
Для того, чтобы отобразить лог-сообщения на экране, используйте такой код:

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a log message.')

Для того, чтобы записывать логи в файл подходит такой код (отличие от предыдущего варианта выделено жирным):

import logging
logging.basicConfig(filename='log_filename.txt',level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a log message.')

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

import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
fh = logging.FileHandler('log_filename.txt')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.debug('This is a test log message.')

Убедитесь, что переменная logging глобальная, так что её смогут видеть все функции (использовать в них gloval logger не нужно, так как эта переменная только для чтения, не для записи и изменения).

Уровни логирования, от более срочных до менее срочных:
  1. CRITICAL
  2. ERROR
  3. WARNING
  4. INFO
  5. DEBUG
Вызов setLevel() устанавливает минимальный уровень логирования, нужный Вам. Например, если Вы используете fh.setLevel(logging.ERROR), тогда будут сообщения  с уровнем WARNING, INFO и DEBUG не будут записываться в файл (так как fh - обработчик лог-файла в нашем примере, в отличие от ch, который обрабатывает логи для отображения на экране).
Для записи сообщен
ий разного уровня используйте
:
  1. logger.critical('This is a critical message.')
  2. logger.error('This is an error message.')
  3. logger.warning('This is a warning message.')
  4. logger.info('This is an informative message.')
  5. logger.debug('This is a low-level debug message.')
На самом деле Вы можете делать гораздо больше, но это всё, что Вам надо знать, чтобы больше не использовать print для отладки программ.
Кроме того, функция pprint.pprint() хороша для вывода словарей и списков, особенно вложенных. Попробуйте и увидите.

Последний совет: Вы можете использовать команду tail -f logfile.txt чтобы посмотреть файл, куда будет записываться информация. Опция -f означает “follow (следовать)”. Просто оставьте окно терминала открытым с запущенной командой, и в нем автоматически будет появляться записываемый в файл текст. Этот способ избавит Вас от необходимости открывать текстовый редактор.
Команда tail присутствует на Mac OS X и Linux / *nix. На Windows Вы можете использовать для её получения проект Cygwin.

Автор: Ishayahu Lastov

7.3.5. namedtuple() — фабричная функция для кортежей с именованными полями

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

collections.namedtuple(typenamefield_namesverbose=Falserename=False)
Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания кортежеподобных объектов, поля которых доступны как для просмотра через атрибуты, так и для индексации и итерации. Экземпляры этого подкласса так же содержат строку документации (с именем типа и именами полей)  и полезный метод __repr__(),который отображает содержимое кортежа в форме name=value.

field_names — одна строка, где каждое имя поля отделено от другого пробелами и/или запятыми, например 'x y' or 'x, y'. Кроме того, в этом параметре можно передать последовательность строк ['x', 'y'].
Любые корректные идентификаторы Python могут использоваться в качестве имён полей, за исключением имён, начинающихся с нижнего подчёркивания. Корректные идентификаторы состоят из букв, цифр и нижних подчёркиваний, но не начинается с цифры или нижнего подчёркивания, а так же не может совпадать с одним из keyword например classforreturnglobalpass, или raise.
Если rename=true, некорректные имена полей автоматически заменяются позиционными именами, например ['abc', 'def', 'ghi', 'abc'] будет преобразовано в ['abc', '_1', 'ghi', '_3'], заменив ключевое слово def и повторяющееся имя поля abc.
Если verbose = true, определение класса будет напечатано после того, как класс будет создан. Эта опция устаревшая, вместо неё проще распечатать атрибут _source.
Экземпляры именованного кортежа не имеют своего личного словаря, так что они занимают не больше места, чем обычные кортежи..
Изменения в версии 3.1: Добавлена поддержка метода rename.
>>>

>>> # простой пример
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # создаём экземпляр с позиционными или именованными аргументами
>>> p[0] + p[1] # можно получать значения по индексу, как в обычном кортеже (11, 22)
33
>>> x, y = p # распаковывается как обычный кортеж
>>> x, y
(11, 22)
>>> p.x + p.y # поля доступны и по именам
33
>>> p # метод __repr__ с форматом name=value
Point(x=11, y=22)
Именованные кортежи особенно полезны для задания имён полей кортежей, возвращаемых модулями csv или sqlite3:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
В дополнение к методам, унаследованным от кортежей, именованные кортежи поддерживают три дополнительных метода и два атрибута. Для того, чтобы предотвратить конфликты с именами полей, эти методы и атрибуты начинаются с нижних подчёркиваний.
classmethod somenamedtuple._make(iterable)
Метод класса, который создаёт новый экземпляр из существующей последовательности или итератора.
>>>

>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()
Возвращает новый OrderedDict который отображает имена полей на соответствующие значения. Обратите внимание, что этот метод уже не требуется, так как тот же самый эффект может быть достигнут при помощи встроенной функции vars():
>>>

>>> vars(p)
OrderedDict([('x', 11), ('y', 22)])
Изменения в версии 3.1: Возвращает OrderedDict вместо обычного dict.
somenamedtuple._replace(kwargs)
Возвращает новый экземпляр именованного кортежа, заменяя определённые пля новыми значениями:
>>>

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

>>> for partnum, record in inventory.items():
... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
somenamedtuple._source
Строка с исходным кодом Python, используемым для создания класса именованного кортежа. Этот код позволяет легко получить документацию для именованного кортежа. Его можно вывести на экран, выполнить при помощи exec(), или сохранить в файл и импортировать.
Добавлено в версии 3.3.
somenamedtuple._fields
Кортеж строк с именами полей. Полезен для интроспекции и для создания новых типов именованных кортежей из уже существующих.
>>>

>>> p._fields            # просмотреть имена полей
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
Чтобы получить значения полей, чьи имена сохранены как строки, используйте функцию getattr():
>>>

>>> getattr(p, 'x')
11
Что преобразовать словарь в именованный кортеж используйте операцию распаковывания словаря (как описано в Unpacking Argument Lists):
>>>

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
Так как именованный кортеж — это обычный класс Python, к нему легко добавлять новую функциональность или изменить уже существующую, просто создавая его подклассы. Тут показано как добавить подсчитываемое поле и изменить формат отображения класса:
>>>

>>> class Point(namedtuple('Point', 'x y')):
__slots__ = ()
@property
def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self):
return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>>

>>> for p in Point(3, 4), Point(14, 5/7):
print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
Подкласс, показанный выше, устанавливает атрибут __slots__ в пустой кортеж. Это помогает сократить использование памяти, не допуская создавать словари для экземпляров.
Подклассы не очень полезны для добавления новых полей. Вместо этого, лучше создать новый тип именованного кортежа, используя атрибут _fields имеющегося:
>>>

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Значения по умолчанию можно реализовать используя метод _replace() для настройки экземпляра прототипа
>>>

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
>>> janes_account = default_account._replace(owner='Jane')
Перечисляемые константы можно задать при помощи именованного кортежа, но  проще сделать это используя  простой класс:
>>>

>>> Status = namedtuple('Status', 'open pending closed&#
39;)._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
open, pending, closed = range(3)
См также

Автор: Ishayahu Lastov

Выражение raise

raise_stmt ::= «raise» [expression [«from» expression]]

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

В противном случае raise выполняет первый expression и получает объект исключения. Он должен являться либо подклассом либо экземпляром BaseException. Если первый expression является именем класса, то создается объект путём вызова класса без передачи аргументов. Читать