Как изменить атрибуты класса в Python с помощью метода без возврата экземпляра (операция на месте)
Описание моей цели и проблемы:
В настоящее время я работаю с пакетами scanpy и anndata в python (версия 3.6.12). Если вы не знакомы с этими пакетами, просто знайте, что
anndata.AnnData
хранит матрицу данных (numpy.ndarray
) в атрибуте
X
. Столбцы
X
описаны в
panda.DataFrame
в
var
атрибут и строки описаны в
obs
атрибут. См. Эту ссылку для получения дополнительной информации
Моя цель - иметь класс (например, класс A), унаследованный от
anndata.AnnData
класс. В этом дочернем классе я хочу реализовать некоторые методы обработки, например, для фильтрации определенных строк или столбцов. Что еще более важно, я также хочу, чтобы эти методы изменяли атрибуты "на месте", без необходимости возвращать копию (т. Е. Без
return self
). Однако, когда я удаляю
return self
в методах экземпляры класса не изменяются. Точнее,
self
изменяется внутри функции, но экземпляр класса остается неизменным.
Пример кода:
Представьте себе следующий пример с классом A, унаследованным от
anndata.AnnData
. У класса A есть один метод, называемый
remove_last_row()
который удаляет последнюю строку (т.е. obs) экземпляра класса A.
import anndata
import numpy as np
class A(anndata.AnnData):
def __init__(self, adata, data_type=None):
"""
Initition method
Parameters:
-----------
adata: anndata.AnnData,
The Anndata object
"""
super().__init__(adata)
def remove_last_row(self):
"""
Remove the last row of the anndata object
"""
print("--> In A.remove_last_row() method:")
print("before filtering: number rows = ", self.X.shape[0])
# get the row index to keep (i.e. the index of the obs without the last one)
index_to_keep = self.obs[:-1].values.astype(int)
# Keep only those index:
self = self[index_to_keep, :]
print("after filtering: number rows = ", self.X.shape[0])
print("<-- exit A.remove_last_row() method.")
Проблема при использовании
remove_last_row()
Метод заключается в том, что строка экземпляра (self) удаляется внутри функции, но не изменяет экземпляр класса. См. Пример ниже:
# Create an AnnData object:
adata = anndata.AnnData(np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]]))
# Create object A that is inherited from AnnData
obj_A = A(adata = adata)
# Test remove_last_row method
obj_A.remove_last_row()
print()
print("obj_A.X attribute = \n", obj_A.X)
Что приводит к:
-> В методе A.remove_last_row():
до фильтрации: количество строк = 3,
после фильтрации: количество строк = 2
<- выйти из метода A.remove_last_row().атрибут obj_A.X =
[[0. 0. 0.]
[1. 1. 1.]
[2. 2. 2.]]
Мы видим это в
remove_last_row()
метод, последняя строка удаляется в
self
внутри функции. Тем не менее
obj_A
(экземпляр класса A) не изменяется этим методом. Как я могу решить эту проблему без добавления
return self
.
Дополнительная информация:
- Версия Python = 3.6.12
- numpy version = 1.19.1
- версия anndata =0.7.4
- версия scanpy =1.6.0
Я также протестировал метод, который назвал
addition()
который добавляет определенное значение к каждому элементу массива
X
. С этим методом я не страдаю этой проблемой.
Если метод
addition()
относится к классу А:
def addition(self, x=1):
"""
Add a value of x for each element in the X numpy array in the AnnData object
Parameters:
-----------
x: float,
The value added to every element
"""
self.X += x
Мы можем протестировать:
# Create an AnnData object:
adata = anndata.AnnData(np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]]))
# Create object A that is inherited from AnnData
print("Before addition")
obj_A = A(adata = adata)
print("obj_A.X attribute = \n", obj_A.X)
# Test the addition method
print()
obj_A.addition(x=1)
print()
print("After addition")
print("obj_A.X attribute = \n", obj_A.X)
Результат:
Перед добавлением
атрибут obj_A.X =
[[0. 0. 0.]
[1. 1. 1.]
[2. 2. 2.]]После добавления
атрибута obj_A.X =
[[1. 1. 1.]
[2. 2. 2.]
[3. 3. 3.]]
Как видите,
addition()
метод сработал. Он смог изменить экземпляр класса.