Я предполагаю, что с 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())

В зависимости от того, хотели ли вы передать класс (тип) или экземпляр класса, вы ищете либо 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, скорее всего, будет абстрактный базовый класс, и некоторые методы здесь могут быть заданы как методы класса.
Боковые примечания к вашему примеру кода:
object (ссылка).CapWord, такими как указано в PEP8, руководство по стилю Python. Следование этому стилю делает ваш код более понятным для других разработчиков.
Вместо того, чтобы объявлять TypeVar и дополнительно привязывать его к Vehicle, у меня также работал Type[Vehicle].