Как изменить атрибуты класса в 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()метод сработал. Он смог изменить экземпляр класса.

0 ответов

Другие вопросы по тегам