#python #slots
Вопрос:
Я знаю, что python использовал утиную типизацию, но мне было интересно, можно ли, в частности, обеспечить проверку типа для переменных класса __slots__
.
например —
class Student:
def __init__(self, name):
self.name = name
class Class:
__slots__ = ('class_representative',
'var_2',
'var_3',
'...', # Assume many more variables below
)
def __init__(self, *args, **kwargs):
self.class_representative = kwargs.get('cr')
self.var_2 = kwargs.get('v2')
self.var_3 = kwargs.get('v3')
... # Assume many more variables below
В приведенном выше примере, как я могу убедиться, что всякий раз, когда какой-либо объект присваивается class_representative
переменной, он всегда должен иметь тип Student
?
Возможно ли что-то вроде следующего?
class Class:
__slots__ = ('class_representative': Student,
'var_2',
'var_3',
'...', # Assume many more variables below
)
Комментарии:
1. Вы должны написать код, чтобы обеспечить это самостоятельно… не уверен, в чем
__slots__
заключается актуальность2. Вы спрашиваете о проверке статической типизации, при которой атрибут получает только
Student
значения, или о проверке во время выполнения?3. @Blckknight Я хочу запретить присваивать какие-либо другие типы, кроме
Student
class_representative
переменных, в любой момент выполнения программы.4. @aaryan: на самом деле это не ответ на мой вопрос. Статическая проверка типов выполняется перед запуском программы и направлена на то, чтобы доказать, что вы никогда не вызывали функцию с неправильным типом. Проверка во время выполнения происходит во время выполнения программы. Они реализованы совершенно по-разному, поэтому вам действительно нужно выбрать, какой из них вы хотите, и сделать это.
__slots__
не имеет ничего общего с проверкой типов (любого вида). Его цель состоит в том, чтобы помочь вам сэкономить память для объектов, которые вы собираетесь создавать в огромном количестве, избегая необходимости__dict__
в каждом экземпляре.5. @Blckknight Извините, что не понял ваш вопрос правильно ранее. Да, я хочу, чтобы здесь была статическая проверка типов. Есть способ, который
Silvio Mayolo
был дан ниже, но он не работает с синтаксисом *args/**kwargs. Смотрите мой комментарий там для получения более подробной информации.
Ответ №1:
Когда вы говорите «статическая типизация», я предполагаю, что вы имеете в виду PEP 484. В этом случае __slots__
не имеет абсолютно никакого значения, и мы аннотируем тип переменных экземпляра так, как мы всегда делаем для классов Python.
class Class:
__slots__ = ('class_representative',)
class_representative: Student
def __init__(self, student: Student) -> None:
self.class_representative = student
Кстати, если вы собираетесь проверять статические типы в Python (что я настоятельно рекомендую; это удивительно хорошо продуманная система), прием и пересылка *args
и **kwargs
в вашем конструкторе-отличный способ потерять любую статическую проверяемость. Возьмите нужные вам аргументы с таким количеством типов, которые вы можете предоставить, и передайте то, что вам нужно.
Комментарии:
1. В некоторых местах у меня есть много аргументов для передачи конструктору. Это будет выглядеть очень некрасиво, если я напишу аргументы так, как вы предложили. Следовательно , я использую
**kwargs
, но затем я теряю статическую проверяемость. Поэтому мне было интересно, есть ли способ каким-то образом указать их__slots__
.2. @aaryan: Я не уверен
**kwargs
, что это делает то, что вы думаете. В вашем примере кода ваш__init__
метод такой же, как если бы его вообще не было. Если вы не реализуете__init__
, вы унаследуетеobject.__init__
, что не принимает никаких аргументов, кроме какself
и ничего не делает. Ваш код принимает произвольные аргументы, но передает ихobject.__init__
, что вызовет исключение, если вообще есть какие-либо аргументы (любых типов). Ничто в вашем классе не будет настраиваться наclass_representative
основе каких-либо аргументов вargs
илиkwargs
, поэтому я не уверен, что вы хотите ввести проверку.3. @Blckknight Я улучшил рассматриваемый пример, чтобы сделать его намного проще для понимания проблемы.
4. Я все еще согласен с @Blckknight. Если вы хотите установить переменную экземпляра
class_representative
в качестве аргументаcr
, просто возьмите вызванный аргументcr
и используйте его.**kwargs
это для тех случаев, когда вы хотите принять все аргументы ключевых слов в качестве словаря. Это совершенно бессмысленно и стоит вам статической проверяемости, если вы знаете, каких аргументов ожидать.5. Кроме того, стоит отметить, просто чтобы убедиться, что нет никаких недоразумений.
__slots__
это в первую очередь трюк с эффективностью, чтобы уменьшить размер класса. Это ни в коем случае не обязательно для класса в Python. Поэтому, если этот класс не используется в экстремальной ситуации с узким местом (и вы провели сравнительный анализ и обнаружили доказательства этого), то__slots__
, вероятно, преждевременно. В частности, это не требуется в классах, и подавляющее большинство классов Python никогда не указывают его