Вопрос или проблема
Например:
In [4]: In [17]: class X:
...: def not_shadow(self, x: list[int]):
...: pass
...:
...: def list(self):
...: list()
...:
...: def shadow_by_X_list_method(self, x: list[int]):
...: pass
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 1
----> 1 class X:
2 def not_shadow(self, x: list[int]):
3 pass
Cell In[4], line 8, in X()
5 def list(self):
6 list()
----> 8 def shadow_by_X_list_method(self, x: list[int]):
9 pass
TypeError: 'function' object is not subscriptable
Я ожидал, что имена функций класса будут доступны только как члены переменной self.
Это особенность правил области видимости!
Хотя это может показаться удивительным, как отмечает @jonsharpe в комментарии, это поведение такое же, как и везде в Python, и позволяет поздним методам и их аргументам ссылаться на более ранние методы в общем
В их примере они отмечают @property
, который добавляет дополнительные методы непосредственно к оборачиваемому методу
Сокращено из документации https://docs.python.org/3/library/functions.html#property.getter
class Foo:
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter # <-- свойство более раннего x
def x(self, value):
self._x = value
Ответ или решение
Вопрос о том, почему методы класса в Python затеняют имена из внешней области видимости, особенно в контексте аннотаций типов, интересен и связан с особенностями работы системы имен в Python.
Когда вы определяете метод в классе, как в вашем примере с методом list
, название метода list
затеняет встроенное имя типа list
. Это означает, что в рамках области видимости класса метод list
теперь доступен вместо встроенной функции list
. Поэтому, когда вы пытаетесь использовать аннотацию типа list[int]
в методе shadow_by_X_list_method
, Python интерпретирует это как попытку использовать метод класса list
, а не встроенный тип list
. Поскольку метод класса — это объект функции, он не поддерживает индексацию, что и приводит к ошибке TypeError: 'function' object is not subscriptable
.
Такое поведение является частью языковых правил Python и позволяет методам и их аргументам ссылаться на другие методы внутри того же класса. Это обеспечивает гибкость проектирования, но требует от разработчиков внимательности к именованию, чтобы избегать затенения встроенных имен. Чтобы избежать этой проблемы, можно использовать альтернативные названия для методов, чтобы сохранить доступ к встроенным типам.
Вот несколько рекомендаций, чтобы избежать этой путаницы:
-
Избегайте имен, совпадающих с встроенными типами: Используйте уникальные имена для методов, чтобы не затенять встроенные функции и типы, такие как
list
,str
,int
и т.д. -
Явное указание на встроенные типы: Если вам действительно нужно использовать такое имя, вы можете явно указывать на встроенное имя в своих аннотациях, например, используя
typing.List
вместоlist
для аннотаций типов. - Проверка и переименование: Перед добавлением нового метода проверьте, нет ли конфликтов с другими методами класса или встроенными типами.
В итоге, важно помнить, что это часть спецификации языка, и, хотя в начале может показаться неожиданным, оно позволяет создавать более сложные структуры и отношения между методами в рамках классов.