Python 2: написание программ и их поддержка

Раздел: Python -> Версии Python

Программы на 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)  # 2

Python 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 метакласс задаётся как атрибут класса, а не как параметр.

программы на Python 2 - comments

En
программы на python 2 (python)