Функция типа в Python (type()-Funktion)

Функция типа в Python (type()-Funktion) Программирование и разработка

Функция Python type() — это базовая функция Python для работы с типами. Как часть реализации Python, это часть ядра языка.

Для чего нужна функция type() в Python?

Функция type() используется в Python для двух очень разных вариантов использования :

  1. Получить тип объекта Python
  2. Динамически создать новый тип

Сначала рассмотрим первый случай. Это гораздо полезнее в повседневном использовании.

Используйте type() для определения типа объекта

Python — это язык с динамической типизацией. Это означает, что типы определяются во время выполнения и привязываются к значениям, а не к переменным. Это обстоятельство приводит к необходимости определения типа объекта во время выполнения.

Мы вызываем функцию Python type(), передавая объект в качестве единственного параметра. В качестве возврата мы получаем тип объекта, например. Б. intили str:

# Type of `42` is `int`
assert type(42) == int
# Type of `str(42)` is `str`
assert type(str(42)) == str

Если мы вызовем функцию type() в Python REPL, текстовое представление будет содержать «класс» вместо «тип» :

# Returns "<class 'int'>" inside REPL
type(42)

То, что на первый взгляд кажется запутанным, имеет смысл, потому что в Python применяется следующее: «Все является объектом». В Python тип объекта — это его класс. Таким образом, вызов функции type() обычно эквивалентен чтению атрибута __class__:

# Should hold in most cases
assert type(obj) is obj.__class__

Создайте новый тип с помощью type()

Теперь давайте посмотрим на второе использование функции type(). Функция, вызываемая с тремя аргументами, позволяет нам динамически создавать новый тип:

type(name, bases, dict, **kwds)

В этой форме функция Python type() действует аналогично ключевому classслову. Код примерно соответствует следующему определению класса:Type = type(«Type», bases, dict)

class <Type>(<bases>):
  <dict>

Ниже мы покажем несколько конкретных примеров использования функции Python type() для создания новых типов. Сначала обзор аргументов:

name bases dict **kwds
Имя нового типа в виде строки Кортежи с базовыми классами Dict с атрибутами нового класса Дополнительные аргументы в пользу создания экземпляра метакласса

Как работает функция Python type()?

При использовании функции type() для определения типа объекта возвращаемое значение является не строкой, а отдельным объектом :

# Value returned by `type(42)` is not a string
assert type(42) != 'int'
# We get back an object named `int`
assert type(42) == int

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

# Python objects of different types
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Print out the type of each object
for obj in different_objs:
  print(f"{obj}: {type(obj)}")
вызов типа() Текстовое представление
type(None) <class ‘NoneType’>
type(True) <class ‘bool’>
type(42) <class ‘int’>
type(‘John’) <class ‘str’>
type((‘Walter’, ‘White’)) <class ‘tuple’>
type(…) <class ‘ellipsis’>
Читайте также:  Советы и секреты эффективной обработки исключений в C Полное руководство

Возникает вопрос: каков тип объекта, возвращаемого функцией type() ? Давай попробуем. Мы вызываем функцию Python type() и передаем возвращаемое значение другого вызова type():

# Returns: "<class 'type'>"
type(type(42))

Мы видим: помимо встроенной в Python функции type() существует тип с таким же именемtype. Это тип всех других типов Python, как мы показываем:

# DifferentPython objects
different_objs = None, True, 42, 'John', ('Walter', 'White'), ...
# Check the type of each object's type
for obj in different_objs:
  # Show that the type's type is always `type`
  assert type(type(obj)) is type

Таким образом, тип любого типа Python — это type. Если это звучит запутанно, то это еще лучше: даже тип объекта typeсноваtype. Это продолжается вечно, как змея, кусающая себя за хвост:

# It's `type` all the way down
assert type(type(type(type))) is type

Устранение путаницы требует более глубокого понимания ООП-системы Python. Встроенный typeобъект Python представляет то, что называется метаклассом. Метакласс относится к классу так же, как класс к объекту. Другими словами, метакласс — это шаблон для класса, а класс — это шаблон для объекта:

Template Instanz
Klasse Objekt
Metaklasse Klasse
Beispiel: type intstretc.
Beispiel:int 42
Beispiel: str “Walter White”

Как функция type() используется в Python?

Функция Python type() обычно используется для определения типа объекта во время выполнения. Это полезно, потому что Python — язык с динамической типизацией. В статически типизированном языке, таком как Java, тип привязывается к переменной посредством объявления и не может быть изменен во время выполнения:

// Declare variable as `boolean`
boolean answer;
// Attempting to assign `int` value
// Throws type error
answer = 42;

Напротив, переменные в Python — это просто имена, которые относятся к типизированным значениям. В любой момент выполнения кода имя может ссылаться на значение другого типа. Итак, чтобы определить тип переменной Python во время выполнения, нам нужна функция type():

# Assign boolean value
answer = True
# Show that type is `bool`
assert type(answer) is bool
# Reassign integer value
answer = 42
# Show that type is now `int`
assert type(answer) is int

Проверьте аргументы функции в Python на их тип

При определении функции часто необходимо проверять аргументы по определенным критериям. Например, аргумент может находиться только в определенных пределах или разрешены только аргументы подходящих типов. Это позволяет избежать ошибок во время выполнения.

Давайте воспользуемся примером, чтобы проиллюстрировать использование функции type(): Мы определяем функцию, которая суммирует список чисел. Чтобы это работало, нам нужно убедиться, что каждый аргумент на самом деле является числом. Мы используем type() внутри assertоператора:

# Function to add up numeric arguments
def add_numbers(*args):
  result = 0
  # Check each argument
  for arg in args:
    # Abort with error message if argument is not an `int` or `float`
    assert type(arg) in (int, float), f"Argument `{arg}` is not a number"
    # Add argument's value to total
    result += arg
  return result

# Show that it works for numbers
assert add_numbers(35, 7) == 42
# The following will fail
add_numbers(29, 'thirteen')

Отладка Python REPL с помощью функции type()

Одним из преимуществ использования интерпретируемого языка, такого как Python, является то, что код может выполняться интерактивно в REPL (Read-Eval-Print-Loop). Такой подход позволяет быстро создавать прототипы и выполнять прямую отладку путем проверки объектов в памяти.

Читайте также:  Комплексное руководство по использованию when и условных паттернов в языке программирования F

Давайте представим следующий сценарий: наш код содержит переменную answer, которая должна содержать логическое значение. Мы определяем, что тип не соответствует ожидаемому, и используем функцию Python type() для вывода фактического типа. Как оказалось, мы случайно написали логическое значение в кавычках — распространенная оплошность среди новичков:

# Accidentally set to string
answer = 'False'
# Assertion will fail
assert type(answer) is bool
# Correct to boolean value
answer = False
# Now assertion holds
assert type(answer) is bool

Динамически создавать классы Python с помощью функции type()

Как мы видели, классы Python можно создавать динамически, то есть во время выполнения, с помощью функции type(). Это полезно, помимо прочего, для семейств классов, которые мы проиллюстрируем на примере тегов HTML. Во-первых, мы создаем базовый класс Tag, объекты которого могут представлять себя в виде HTML-кода:

# Class representing HTML tag
class Tag:
  # Initialize HTML tag with contents
  def __init__(self, *args):
    # Join contents of tag
    self.content = "".join([arg.__str__() for arg in args])
  # String representation returns HTML
  def __str__(self):
    return f"<{self.name}>{self.content}</{self.name}>"

Затем мы специализируем базовый класс путем наследования для соответствующих конкретных тегов, таких как или. Для этого мы вызываем функцию type() с тремя аргументами:

# Create `P` class
P = type('P', (Tag,), {"name": 'p'})

1. Имя нового класса в виде строки.

2. Кортежи с базовыми классами.

Python допускает множественное наследование; чтобы вывести только из одного класса, мы используем обозначение.(ClassName,)

3. Dict с названием класса и любыми другими записями.

Записи также могут быть функциями.

Затем мы создаем экземпляр pтега и проверяем правильность рендеринга:

# Instantiate `p` tag
greeting = P("Hello world")
assert str(greeting) == '<p>Hello world</p>'

Тот же эффект может быть достигнут с помощью аналогичного определения класса :

# Create `P` class
class P(Tag):
  name = 'p'

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

h_1_to_6 = ( f"h{n}" for n in range(1, 7) )
headings = [type(heading, (Tag,), {"name": heading}) for heading in h_1_to_6]

Как мы показали, стоит использовать функцию type() для удобного создания нескольких связанных подклассов. Мы покажем этот подход на более сложном примере определения классов для моделирования игральных карт. Во-первых, мы определяем суперкласс Cardпо classключевому слову:

# Class representing abstract playing card
class Card:
  def __init__(self, number):
    self.number = number
  # String representation
  def __str__(self):
    return f"{self.number} of {self.suite}"

Затем мы создаем подклассы для четырех мастей карт, используя type():

# Create concrete types for each suite
Clubs = type('Clubs', (Card,), {'suite': 'Clubs'})
Diamonds = type('Diamonds', (Card,), {'suite': 'Diamonds'})
Hearts = type('Hearts', (Card,), {'suite': 'Hearts'})
Spades = type('Spades', (Card,), {'suite': 'Spades'})

Отдельные карты теперь могут быть созданы без проблем :

# Instantiate a 7 of Spades
card = Spades(7)
# Show that it worked
assert str(card) == '7 of Spades'

Где функция type() достигает своего предела?

Функция Python type() полезна. Однако есть некоторые случаи использования, когда функция достигает своих пределов, когда дело доходит до их решения. К счастью, Python знает соответствующие подходы; давайте посмотрим на некоторые из них.

Читайте также:  Как создать кнопку прокрутки в Jetpack Compose — исчерпывающее руководство

Разбейте иерархию наследования с помощью isinstance()

type() определяет только фактический тип объекта Python, игнорируя иерархию наследования. Мы проиллюстрируем возникшую дилемму на примере с игральными картами из предыдущего раздела. Тип пиковой 7 должен быть как «игральной картой», так и «пиковой». Однако это нельзя определить с помощью type():

# Create a Seven of Spades
card = Spades(7)
# Our card is a Spade alright
assert type(card) is Spades
# But not a card??
assert type(card) is not Card

Чтобы правильно декодировать лежащий в основе полиморфизм, мы используем функцию.isinstance()

# Seven of Spades is a `Spade`
assert isinstance(card, Spades)
# And is also a `Card`
assert isinstance(card, Card)

Упростите определение типа объекта Python с помощью match-case

Как мы показали ранее, функция type() часто используется для определения типа объекта во время выполнения. Чтобы различать несколько возможных типов, можно использовать конструкцию :if-elif-else

# Determine type of object
if type(obj) is int:
  print("Int")
elif type(obj) is float:
  print("Float")
elif type(obj) is ...:
  print("...")
else:
  print("Something else")

Однако, начиная с версии 3.10, Python знает это утверждение. Помимо прочего, это позволяет распознавать типы без вызова функции type().match-case

caseФункции конструктора, подобные или, могут использоваться внутри блока. Блок соответствует, если объект имеет соответствующий тип:int(obj)str(obj)

# Example object
obj = 42
# Determine object type
match obj:
  case int(obj):
    print(f"{obj} is `int`")
  case float(obj):
    print(f"{obj} is `float`")
  case _:
    print(f"{obj} is something else")

Оцените статью
Блог о программировании
Добавить комментарий