columns
не определен ни в одном месте. Это просто атрибут в DataFrame, который указывает на экземпляр другого объекта. В частности, columns
должен быть экземпляром pandas.core.indexes.base.Index
или одним из его подклассов, которые также определены в подмодулях pandas.core.indexes
, но также в основном доступны из модуля верхнего уровня (например, pd.RangeIndex
).
Я различаю «определенное» от двух возможных связанных идей:
- Где установлен атрибут. (например, строка, где они go,
self.columns = ...
). - Как объект DataFrame использует / взаимодействует с атрибутом.
Где определено Index
?
Фактический путь к базовому Index
классу:
https://github.com/pandas-dev/pandas/blob/v1.0.3/pandas/core/indexes/base.py#L177
Аналогично, в вашей локальной установке он будет
[..]/python3.x/site-packages/pandas/core/indexes/base.py
.
Где написано, что columns
должен быть экземпляром Index
?
Так как python не является строго типизированным, это своего рода трудно доказать / обеспечить соблюдение. Однако DataFrame
наследуется от NDFrame
, что является его N-мерным обобщением (Series
является одномерной версией). В конце дня NDFrame
сохраняет данные в атрибуте с именем ... _data
, который является экземпляром BlockManager
. Здесь вы можете видеть, что печатные символы на axes
(columns
- это своего рода ось) имеют вид Index
. Все (ортодоксальные) модификации этих осей будут проходить через функцию ensure_index
, которая преобразует, например, списки в правильные индексы.
Как установить атрибут column
и найдено?
(Может быть, это был главный вопрос?)
Индексный объект, на который columns
ссылается, живет в pd.DataFrame._data.axes[0]
. Пользовательские реализации __getattr__
и __setattr__
гарантируют, что вызов DataFrame.columns
вернет этот элемент.
Но позвольте мне вернуться.
Вызов метода класса _setup_axes
изменяет класс DataFrame
(экземпляр , а не ) на атрибуты columns
и index
.
* 1080. * В частности,
_setup_axes
устанавливает атрибут
columns
как
AxisProperty
с аргументом
axis=0
. Возможно, вы могли бы думать о
_setup_axes
как об обещании, что каждый экземпляр
DataFrame
будет иметь метки для двух осей и, кроме того, что у этих осей есть имена.
Так почему же вызовы df.columns
возвращают Индекс, а не AxisProperty
?
Вызов на df.columns
будет:
- Ввести
__getattr__
. - Найдите
columns
среди записей в self._internal_names_set
, поэтому go в строку 5270 - [5270]
return object.__getattribute__(self, name)
. - Триггеры
__get__
метод AxisProperty
. Обратите внимание, что вторым аргументом здесь (obj
) является наш экземпляр DataFrame (!). - On 63 access
obj._data.axes
, т.е. атрибут _data[.axes]
кадра данных. - On 64 вернуть элемент
obj._data.axes
, соответствующий self.axis
. Вызов _setup_axes
установил self.axis=0
, поэтому мы получаем 0-й элемент.
Установка df.columns
(после инициализации) работает аналогичным образом. Когда DataFrame инициализируется, столбцы преобразуются в тип Index
, добавляются в список осей и передаются в качестве аргумента для инициализации BlockManager
, который затем присваивается атрибуту _data
.