Как работают преобразования типов

Раздел: Основы Python -> Преобразование данных

Преобразование типов в Python: базовый подход

Основной путь в Python связан с вызовом типа как функции. Конструкторы int(), float(), str(), bool(), list(), tuple(), set(), dict(), bytes() создают объект нового типа на основе переданного значения. Если преобразование невозможно, интерпретатор сообщает об ошибке.


# Пример базовых преобразований
age = int('42')
price = float('19.95')
text = str(100)
flag = bool(0)
items = list((1, 2, 3))
coords = tuple([4, 5])
user = dict([('name', 'Anna'), ('age', 30)])
unique = set([1, 2, 2, 3])
data = bytes('привет', encoding='utf-8')

print(age)
print(price)
print(text)
print(flag)
print(items)
print(coords)
print(user)
print(unique)
print(data.decode('utf-8'))

Python список цифр в число (преобразование списка цифр в число в python)

42
19.95
100
False
[1, 2, 3]
(4, 5)
{'name': 'Anna', 'age': 30}
{1, 2, 3}
привет

Python преобразование типов (преобразование типов в python)

Каждый шаг создаёт новый объект. Целые числа, строки и кортежи неизменяемы, поэтому исходное значение остаётся прежним. Списки, словари и множества могут быть созданы из других коллекций. Для строк в bytes явно указывается кодировка, потому что байты и текст относятся к разным уровням представления данных.

Ошибки возникают при несовместимых типах: int('12.5') даёт ValueError, int(None) даёт TypeError, dict([1, 2]) даёт TypeError, list(10) даёт TypeError. Причина в том, что Python не выполняет неявное приведение там, где возможна потеря данных или неоднозначность. Проверка isinstance() и конструкция try/except дают предсказуемое поведение.

Как преобразовать число в строку с нужной точностью?

Функция str() даёт краткое представление. Форматные строки и format() управляют округлением, разделителями и выравниванием. Такой подход применяется для отчётов, логов и пользовательского вывода.


value = 1234.56789
print(str(value))
print(format(value, '.2f'))
print(f'{value:,.2f}')
print(f'{255:08b}')
print(f'{42:x}')

Python функции преобразования (функции преобразования в python)

1234.56789
1234.57
1,234.57
11111111
2a

str() не меняет число. format() возвращает новую строку. f-строка вычисляет выражение и подставляет результат. Округление в format() выполняется по правилам двоичного представления float, поэтому Decimal подходит для денежных расчётов.

Типичная ошибка: ожидание, что str(0.1 + 0.2) даст '0.3'. На практике появляется '0.30000000000000004'. Для финансовых значений применяется decimal.Decimal или округление на этапе вывода.

Как преобразовать строку в число при неизвестном формате?

Базовые int() и float() принимают строки с пробелами и знаками. Для запятых, валют и процентов требуется предварительная очистка. Decimal сохраняет десятичную точность, Fraction работает с рациональными числами.


from decimal import Decimal
from fractions import Fraction

print(int('  -15  '))
print(float('1_000.5'))
print(Decimal('19.99'))
print(Fraction('3/4'))

raw = '1 234,50 руб.'
clean = raw.replace(' ', '').replace(',', '.').replace('руб.', '')
print(float(clean))
-15
1000.5
19.99
3/4
1234.5

int() не принимает десятичную точку. float() принимает точки и экспоненту. Decimal получает строку и не проходит через двоичное округление. Очистка строки зависит от локали и формата источника.

Ошибка ValueError появляется при пустой строке, лишних символах или неверном разделителе. Для пользовательского ввода помогает регулярное выражение и замена разделителей. Нельзя считать, что запятая всегда десятичный разделитель: в части локалей она разделяет тысячи.

Как связаны bool, int и float?

bool является подклассом int. False равен 0, True равен 1. Функция bool() использует протокол истинности: пустые коллекции, 0, None и пустые строки дают False.


print(True + True)
print(int(True), int(False))
print(bool(0), bool(0.0), bool(''), bool([]), bool({}))
print(bool('0'), bool([0]), bool(-1))
print(1 == True, 0 == False)
2
1 0
False False False False False
True True True
True True

Арифметика с bool возможна, но ухудшает читаемость. Явное int(flag) или float(flag) показывает намерение. Проверка if value: использует bool(value) неявно.

Опасность: строка 'False' не равна False. bool('False') даёт True, потому что строка непустая. Для разбора текстовых флагов нужна отдельная логика сравнения с 'true', 'false', '1', '0'.

Как преобразовать коллекции между list, tuple, set и dict?

Конструкторы list(), tuple(), set() принимают любой итерируемый объект. dict() ожидает пары ключ-значение или именованные аргументы. Преобразование создаёт новый контейнер, но вложенные объекты не копируются глубоко.


source = [('a', 1), ('b', 2)]
mapping = dict(source)
print(mapping)
print(list(mapping))
print(tuple(mapping))
print(set([1, 2, 2, 3]))
print(dict(a=1, b=2))
print(dict.fromkeys(['x', 'y'], 0))
{'a': 1, 'b': 2}
['a', 'b']
('a', 'b')
{1, 2, 3}
{'a': 1, 'b': 2}
{'x': 0, 'y': 0}

set() удаляет дубликаты и меняет порядок. list(mapping) даёт ключи. dict() из списка пар сохраняет порядок вставки. dict.fromkeys() создаёт словарь с одинаковым значением по умолчанию.

Ошибка: dict([1, 2, 3]) вызывает TypeError, потому что элементы не являются парами. Для вложенных списков подходит dict() только при длине элемента 2. Изменяемые ключи, например list, недопустимы в dict и set.

Как преобразовать str в bytes и обратно?

Текст и байты разделены. str.encode() возвращает bytes, bytes.decode() возвращает str. Кодировка по умолчанию utf-8, но её лучше указывать явно. Обработка ошибок задаётся параметром errors.


text = 'Привет, мир!'
data = text.encode('utf-8')
print(data.hex())
print(data.decode('utf-8'))

broken = bytes([255, 254])
print(broken.decode('utf-8', errors='replace'))
d09fd180d0b8d0b2d0b5d1822c20d0bcd0b8d18021
Привет, мир!
��

hex() показывает байты без escape-последовательностей. errors='replace' заменяет неподходящие байты. Для неизвестной кодировки применяется charset-normalizer или попытки декодирования с несколькими вариантами.

Ошибка UnicodeDecodeError появляется при чтении байтов в неверной кодировке. Ошибка UnicodeEncodeError возникает, если текст содержит символы, отсутствующие в целевой кодировке, например cp1251. Параметр errors='ignore' скрывает проблему, поэтому его применение требует обоснования.

Как сделать безопасное преобразование с обработкой ошибок?

Для внешних данных применяется try/except. Функция возвращает значение или значение по умолчанию. Такой приём используется в парсингах, API и файлах конфигурации.


def to_int(value, default=None):
    try:
        return int(value)
    except (TypeError, ValueError):
        return default

print(to_int('42'))
print(to_int('4.2'))
print(to_int(None, 0))
print(to_int('abc', -1))
42
None
0
-1

Перехват конкретных исключений не скрывает ошибки программирования. Значение по умолчанию должно быть отделено от валидного результата. Для сложных схем подходит pydantic, dataclasses с валидацией или typing в сочетании с проверками.

Ловушка: except Exception скрывает опечатки и системные ошибки. Другая проблема: возврат None для отсутствия значения может конфликтовать с реальным None. В таких случаях применяется sentinel-объект или исключение.

Расширенные примеры преобразований в Python

Примеры показывают взаимодействие с протоколами языка, стандартной библиотекой и внешними форматами. Каждый блок содержит код и результат.

Пользовательские классы и специальные методы

Класс может определять преобразование через __int__, __float__, __str__, __bool__ и __index__. Вызов int(obj) ищет __int__ или __index__, float(obj) ищет __float__, str(obj) использует __str__, bool(obj) использует __bool__ или __len__.

Пример

class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    def __int__(self):
        return int(self.celsius)

    def __float__(self):
        return float(self.celsius)

    def __str__(self):
        return f'{self.celsius} C'

    def __bool__(self):
        return self.celsius != 0

t = Temperature(21.7)
print(int(t))
print(float(t))
print(str(t))
print(bool(t))
print(bool(Temperature(0)))
21
21.7
21.7 C
True
False

Ошибка возникает, если __int__ возвращает не int, а, например, float. Python требует точный тип. Для среза и hex() нужен __index__, а не __int__.

__index__ для индексов и систем счисления

Пример

class Index:
    def __index__(self):
        return 3

idx = Index()
items = [10, 20, 30, 40]
print(items[idx])
print(hex(idx))
print(bin(idx))
print(oct(idx))
40
0x3
0b11
0o3

Decimal и Fraction

Decimal хранит десятичные дроби без двоичного шума. Fraction строит рациональное число из строки, float или Decimal.

Пример

from decimal import Decimal, ROUND_HALF_UP
from fractions import Fraction

d = Decimal('2.675')
print(d.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
print(int(d))
print(float(d))
print(Decimal.from_float(0.1))
print(Fraction(0.5))
print(Fraction('0.25'))
print(Fraction(Decimal('0.1')))
2.68
2
2.675
0.1000000000000000055511151231257827021181583404541015625
1/2
1/4
1/10

Decimal.from_float показывает точное двоичное представление. Для денег используется Decimal('0.1'), а не Decimal(0.1). Иначе в число попадает двоичная погрешность.

Даты и временные метки

Пример

from datetime import datetime, timezone

dt = datetime(2024, 1, 2, 3, 4, 5, tzinfo=timezone.utc)
ts = dt.timestamp()
print(ts)
print(datetime.fromtimestamp(ts, tz=timezone.utc))
print(dt.isoformat())
1704164645.0
2024-01-02 03:04:05+00:00
2024-01-02T03:04:05+00:00

JSON и ручное приведение полей

Пример

import json

raw = {'id': '10', 'price': '19.99', 'active': 'true'}
data = dict(raw)
data['id'] = int(data['id'])
data['price'] = float(data['price'])
data['active'] = data['active'] == 'true'
print(data)
print(json.dumps(data))
print(type(data['id']))
print(type(data['price']))
print(type(data['active']))
{'id': 10, 'price': 19.99, 'active': True}
{"id": 10, "price": 19.99, "active": true}



json.loads уже создаёт int, float, bool. Если поле пришло строкой, тип остаётся str. Автоматическая замена типов по значению опасна: строка '0' может быть идентификатором, а не числом.

CSV и преобразование строк таблицы

Пример

import csv

rows = list(csv.DictReader(['id,price', '1,10.5', '2,20.0']))
converted = [
    {'id': int(row['id']), 'price': float(row['price'])}
    for row in rows
]
print(converted)
[{'id': 1, 'price': 10.5}, {'id': 2, 'price': 20.0}]

Байты, struct и целые числа

Пример

import struct

number = 123456
packed = struct.pack('!i', number)
print(packed.hex())
print(struct.unpack('!i', packed)[0])
print(int.from_bytes(packed, 'big'))
print(number.to_bytes(4, 'big').hex())
0001e240
123456
123456
0001e240

Base64 и кодировки

Пример

import base64

text = 'Привет'
raw = text.encode('utf-8')
encoded = base64.b64encode(raw)
print(encoded)
print(base64.b64decode(encoded).decode('utf-8'))
b'0J/RgNC40LLQtdGC'
Привет

ast.literal_eval для безопасного разбора простых литералов

Пример

import ast

print(ast.literal_eval('123'))
print(ast.literal_eval('1.5'))
print(ast.literal_eval('[1, 2, 3]'))
print(ast.literal_eval("{'a': 1, 'b': 2}"))
print(ast.literal_eval('True'))
123
1.5
[1, 2, 3]
{'a': 1, 'b': 2}
True

ast.literal_eval не выполняет произвольный код, но принимает только литералы. Выражения, имена переменных и вызовы функций вызывают ValueError. Для сложных схем применяется json.loads или специализированный парсер.

Преобразование через map и генераторы

Пример

values = ['1', '2', '3.5', '4']
ints = list(map(int, values[:2]))
floats = [float(x) for x in values[2:]]
print(ints)
print(floats)
print(sum(ints) + sum(floats))
[1, 2]
[3.5, 4.0]
10.5

Собственный безопасный конвертер

Пример

def convert(value, target, default=None):
    try:
        if target is bool:
            if isinstance(value, str):
                return value.strip().lower() in {'1', 'true', 'yes', 'on'}
            return bool(value)
        return target(value)
    except (TypeError, ValueError):
        return default

print(convert('42', int))
print(convert('3.14', float))
print(convert('true', bool))
print(convert('no', bool))
print(convert('abc', int, 0))
42
3.14
True
False
0

Для bool нельзя применять bool('False'), потому что непустая строка истинна. Отдельная проверка текстовых значений устраняет эту ловушку. Значение по умолчанию стоит выбирать так, чтобы оно отличалось от валидных данных.

Преобразование типов в аннотациях и typing

Пример

from typing import Union

def parse_port(value: Union[str, int]) -> int:
    port = int(value)
    if not 1 <= port <= 65535:
        raise ValueError('port out of range')
    return port

print(parse_port('8080'))
try:
    print(parse_port(0))
except ValueError as error:
    print(error)
8080
port out of range

Аннотации не выполняют преобразование во время работы. Они служат документацией и проверяются инструментами вроде mypy. Фактическое приведение выполняет код внутри функции.

Преобразование типов в Python - comments

En
Python преобразование типов (python)