Python - как перейти к типу аргумента функции объекта класса (ввод)

Я предполагаю, что с python 3.7 (не уверен) появилась возможность передавать в функцию не только имя переменной, но и тип переменной. Я хотел бы знать, есть ли возможность передать тип определенного класса.

Так же, как вы могли бы пройти:

def foo_func(i: int) -> None:
    pass

Если у меня есть класс, скажем:

class foo_class(object):
    pass

Как я могу преобразовать foo_func, чтобы получить foo_class вместо intтипа?

Кроме того, если бы foo_class был унаследован от другого класса, мог бы я навязать более общий тип от родителя? Например, если бы я имел,

class A(foo_class):
     pass

class B(foo_class):
     pass

Как я мог передать A или B на основе его родителя?

Я имею в виду что-то вроде:

def foo_func(obj: foo_class_type) -> None:
    pass

foo_func(A())
foo_func(B())
Что такое компоненты React? Введение в компоненты | Типы компонентов
Что такое компоненты React? Введение в компоненты | Типы компонентов
Компонент - это независимый, многократно используемый фрагмент кода, который делит пользовательский интерфейс на более мелкие части. Например, если мы...
10
0
7 955
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В зависимости от того, хотели ли вы передать класс (тип) или экземпляр класса, вы ищете либо typing.Type, либо просто класс.

Вот простой пример, объясняющий обе ситуации:

from typing import Type, TypeVar


class Vehicle:
    def __init__(self):
        print("Creating a %s" % self.__class__.__name__)

    def move(self):
        print("This %s is moving…" % self.__class__.__name__)

TVehicle = TypeVar("TVehicle", bound=Vehicle)

class Car(Vehicle):
    def honk(self) -> None:
        print("tuuuuut")

class Bike(Vehicle):
    def ring(self) -> None:
        print("ring")

class Dog:
    def bark(self) -> None:
        print("woof!")


def move(v: Vehicle) -> None:
    v.move()

def instantiate(class_to_instantiate: Type[TVehicle]) -> TVehicle:
    return class_to_instantiate()  # create an instance

move(Bike())
move(Car())

instantiate(Bike).ring()
instantiate(Car).honk()
#instantiate(Dog)

Car и Bike наследуются от Vehicle, поэтому они оба получают как минимум метод move и пользовательский __init__, который раскрывает имя класса, вызвавшего его.

Теперь в первой функции move нужно просто указать, что аргумент v должен быть пример для Vehicle. Функция вызывает метод Vehiclemove, который раскрывает имя класса экземпляра, из которого исходит вызов.

Целью второй функции, instantiate, является создание экземпляра класса. Это работает через переменные типа, что позволяет вам в этом примере указать, что существует связь между входным аргументом функции и выходным аргументом: если бы я вызывал instantiate(Bike), я хочу, чтобы возвращаемый тип был экземпляром класса Bike, так что я может законно вызывать свой метод ring. Если бы вы заменили TVehicle в этом определении функции просто на Vehicle, ваша программа проверки типов пожаловалась бы, потому что возвращаемый тип был бы экземпляром класса Vehicle, для которого у вас нет гарантии, что метод ring существует. Наконец, часть Type, которую вы видите в аргументе instantiate, просто позволяет вам вызывать функцию с классом, а не с экземпляром этого класса. Это полезно, например. в случаях, когда вы хотите отложить создание экземпляра класса.

Обратите внимание, что это пример, чтобы объяснить, как это сделать. В более профессиональных условиях Vehicle, скорее всего, будет абстрактный базовый класс, и некоторые методы здесь могут быть заданы как методы класса.

Боковые примечания к вашему примеру кода:

  1. Обратите внимание: если вы не собираетесь писать код, который также работает в Python2, вам не следует наследовать от object (ссылка).
  2. Классы обычно пишутся с именами CapWord, такими как указано в PEP8, руководство по стилю Python. Следование этому стилю делает ваш код более понятным для других разработчиков.

Вместо того, чтобы объявлять TypeVar и дополнительно привязывать его к Vehicle, у меня также работал Type[Vehicle].

Blaze 08.11.2021 17:37

Другие вопросы по теме