Python 2: написание программ и их поддержка
Программы на Python 2: основные подходы и примеры
Наиболее эффективный способ написания программ на Python 2 - это использование конструкции future imports, которая позволяет применять синтаксис Python 3, оставаясь в среде Python 2. Такой подход облегчает последующий переход на актуальные версии и уменьшает количество ошибок. Ниже приведён шаблон программы, который учитывает ключевые различия.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
def main():
# Пример: работа с вводом и выводом
имя = raw_input("Введите ваше имя: ") # raw_input возвращает str (bytes в Python 2)
print("Привет, {}!".format(имя))
# Деление теперь возвращает float
print("5 / 2 = {}".format(5 / 2)) # 2.5
if __name__ == "__main__":
main()Python 2 import (импорт в python 2)
Этот код работает в Python 2.7 и при этом использует print как функцию, обычное деление (float) и поддержку Unicode. Такой подход рекомендуется для всех новых проектов на Python 2, особенно если планируется миграция на Python 3.
Типичные ошибки:
- Забыть импортировать unicode_literals - строки по умолчанию будут байтовыми, что может вызвать проблемы с кодировками.
- Использовать input() вместо raw_input() - в Python 2 input() пытается вычислить введённое выражение, что может быть опасно.
- Не указывать кодировку файла (# -*- coding: utf-8 -*-), что приведёт к ошибке SyntaxError при наличии не-ASCII символов.
Решение: всегда добавлять future imports и явно указывать кодировку в начале файла.
Как сделать, чтобы в Python 2 print работал как функция, а не оператор?
Необходимо импортировать print_function из модуля __future__. После этого скобки становятся обязательными.
from __future__ import print_function
print("Hello, World!") # ok
print "Hello" # SyntaxErrorпрограммы на python 2 (программы на python 2)
Как правильно обрабатывать ввод чисел, чтобы избежать исключений?
Использовать raw_input(), затем преобразовывать строку в нужный тип. В Python 2 input() эквивалентен eval(raw_input()), что небезопасно.
age = raw_input("Сколько вам лет? ")
# Введённые данные - строка, поэтому преобразуем:
try:
age_int = int(age)
print("Через 10 лет вам будет", age_int + 10)
except ValueError:
print("Ошибка: введите целое число")Python 3 программы (программы на python 3)
Возможная ошибка: забыть обработать исключение при преобразовании - программа упадёт с ValueError.
Как заставить деление работать как в Python 3 (возвращать float)?
Импортировать division из __future__. Тогда / всегда возвращает float, а // - целочисленное деление.
from __future__ import division
print(5 / 2) # 2.5
print(5 // 2) # 2Python 2 print (print в python 2)
Как итерироваться без создания большого списка, как range в Python 3?
В Python 2 функция xrange() работает как ленивый генератор, аналогично range() в Python 3. range() возвращает список.
# range(1000000) создаст список из миллиона чисел
# xrange(1000000) - итератор
for i in xrange(1000000):
if i > 10:
break
print("Итерация завершена")Install python 64 bit (установка python 64-bit)
Проблема: в Python 3 xrange отсутствует, поэтому код не будет переносимым. Решение - использовать range из будущего (после импорта division он не меняется). Лучше писать range и надеяться, что память не переполнится, или использовать внешнюю библиотеку six.
Как корректно обрабатывать исключения в Python 2?
Синтаксис except Exception as e доступен с Python 2.6, но в более старых версиях пишут except Exception, e. Для совместимости лучше использовать современный вариант.
try:
f = open("file.txt")
except IOError as e:
print("Ошибка чтения файла:", e)
Ошибка: в Python 2.5 и младше as не поддерживается, возникает SyntaxError. Если нужна поддержка старых версий, используйте sys.exc_info().
Как сделать классы нового стиля в Python 2?
Унаследовать класс от object. В противном случае создаётся класс старого стиля (нет super(), свойства работают иначе).
class NewStyleClass(object):
def __init__(self, value):
self.value = value
class OldStyleClass: # без наследования
pass
Цель: использование возможностей дескрипторов, super() и унификация поведения.
Дополнительные примеры программ на Python 2
1. Декоратор для логирования вызовов функций
Пример использует functools.wraps для сохранения метаданных. В Python 2 имя функции можно получить через func.__name__.
from __future__ import print_function
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Вызвана функция {} с аргументами {} и {} ".format(func.__name__, args, kwargs))
return func(*args, **kwargs)
return wrapper
@log
def add(a, b):
return a + b
print(add(3, 4))
Вызвана функция add с аргументами (3, 4) и {}
7
2. Генератор чисел Фибоначчи с использованием yield
Генераторы в Python 2 работают как и в Python 3. Разница лишь в том, что next() вызывается через метод .next() у объекта-генератора (или встроенной функцией next()).
def fib(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
for number in fib(100):
print(number, end=' ')
0 1 1 2 3 5 8 13 21 34 55 89
3. Чтение CSV-файла в словарь с помощью csv.DictReader
Модуль csv доступен в обеих версиях. Важно: файл следует открывать в режиме 'rb' для Python 2, иначе строки могут быть повреждены.
import csv
with open('data.csv', 'rb') as f:
reader = csv.DictReader(f)
for row in reader:
print(row['name'], row['age'])
Файл data.csv:
name,age
Alice,30
Bob,25
Alice 30 Bob 25
Если файл открыть в текстовом режиме ('r'), то на Windows символы новой строки могут быть обработаны неверно, а также будет возникать ошибка 'str' object has no attribute 'decode', если в файле есть Unicode-символы.
4. Использование sets (множества) без дубликатов
В Python 2 множества можно создать с помощью литерала {1, 2, 3} (доступно с Python 2.7). Для более старых версий используйте set([1,2,3]).
# Удаление дубликатов из списка
items = [1, 2, 2, 3, 4, 4, 5]
unique = set(items)
print(list(unique))
[1, 2, 3, 4, 5]
5. Работа с urllib2 для загрузки веб-страницы
В Python 2 используется модуль urllib2 (в Python 3 заменён на urllib.request). Ниже пример простого GET-запроса.
import urllib2
try:
response = urllib2.urlopen('http://example.com')
html = response.read()
print(html[:200]) # первые 200 символов
except urllib2.URLError as e:
print('Ошибка загрузки:', e)
<!doctype html>
<html>
<head>
<title>Example Domain</title>... (сокращено)
6. Использование ConfigParser для чтения конфигураций
Модуль ConfigParser (с большой буквы) присутствует только в Python 2. В Python 3 он переименован в configparser. Пример чтения INI-файла:
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('settings.ini')
print(config.get('Database', 'host'))
print(config.getint('Database', 'port'))
Файл settings.ini:
[Database]
host = localhost
port = 5432
localhost 5432
Если в конфигурации присутствуют секции с кириллицей, необходимо указывать кодировку при открытии файла и использовать io.open с encoding='utf-8', иначе возникнет ошибка декодирования.
7. Использование метаклассов для создания синглтона
В Python 2 метакласс задаётся с помощью атрибута __metaclass__ на уровне класса (в Python 3 используется metaclass= в аргументах). Пример:
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class MyClass(object):
__metaclass__ = SingletonMeta
def __init__(self, value):
self.value = value
a = MyClass(10)
b = MyClass(20)
print(a is b) # True
print(a.value, b.value) # 10 10
True 10 10
Пояснение: метакласс переопределяет создание экземпляра, гарантируя, что для каждого класса будет только один объект. Важно: в Python 2 метакласс задаётся как атрибут класса, а не как параметр.