Как изменить значение по умолчанию атрибута класса RS4 — rpy2

#python #r #python-3.x #rpy2

#python #r #python-3.x #rpy2

Вопрос:

Я сопоставляю класс RS4 в Python, выполняя следующее:

 from rpy2.robjects.packages import importr
import rpy2.robjects as ro

class MapTOS4(ro.methods.RS4):
    """
    writing a child class to map to S4 reference class in python
    """
    def LoadFile(self, filename):
        """access the LoadFile method of SlicedData class"""

        return ro.baseenv['$'](self, 'LoadFile')(filename)
    
    def fileSliceSize(self):
        """access the class attribute or field""" 
        return ro.baseenv['$'](self, 'fileSliceSize')
    
mql = importr('MatrixEQTL')
data = MapTOS4(mql.SlicedData())
print(data.fileSliceSize())
  

При выполнении приведенного выше кода я получил следующее, [1] 1000 что ожидаемо, потому что в этом конкретном пакете значение поля / атрибута класса fileSliceSize по умолчанию установлено равным 1000. Тем не менее, я пытаюсь сбросить или изменить значение этого атрибута класса на 2000.

В R это можно легко сделать с помощью следующего простого кода:

 data$fileSliceSize = 2000 
  

Как я могу добиться этого на основе моей реализации в Python?

Заранее большое вам спасибо.

Ответ №1:

В R data$fileSliceSize = 2000 операция — это просто синтаксический сахар для вызова $<- функции с тремя аргументами (объект, ключ, значение):

 library(MatrixEQTL)
data = SlicedData()

`$<-`(data, 'fileSliceSize', 2000)
# SlicedData object. For more information type: ?SlicedData
# Number of columns: 0 
# Number of rows: 0 
# Data is stored in 0 slices
  

так же, как access by data$fileSliceSize является синтаксическим сахаром для:

 `$`(data, 'fileSliceSize')
# [1] 2000
  

Обратные метки используются для экранирования специальных символов в имени функции — вы можете вызвать любую функцию R с обратными метками:

 `print`('text')
# [1] "text"
  

Смотрите больше в главе извлечения документации R.

Следовательно, в rpy2 вы могли бы просто сделать:

 ro.baseenv['$<-'](data, 'fileSliceSize', 2000)
  

Тем не менее, я бы рекомендовал попробовать более «питонический» подход (строки документации опущены для краткости):

 from rpy2.robjects.packages import importr
import rpy2.robjects as ro


# assigning these R operators here will make the code easier to read
# and provide a (negligible in this case) performance increase.
get_r_attribute = ro.baseenv['$']
set_r_attribute = ro.baseenv['$<-']


class MapTOS4(ro.methods.RS4): 

    def __init__(self, r_obj, file_slice_size=2000): 
        super().__init__(r_obj) 
        self.file_slice_size = file_slice_size

    def load_file(self, filename):
        return get_r_attribute(self, 'LoadFile')(filename)

    @property
    def file_slice_size(self):
        return get_r_attribute(self, 'fileSliceSize') 

    @file_slice_size.setter 
    def file_slice_size(self, value): 
        set_r_attribute(self, 'fileSliceSize', value)


mql = importr('MatrixEQTL') 
data = MapTOS4(mql.SlicedData()) 
print(data.file_slice_size)
# prints 2000
data.file_slice_size = 3000
print(data.file_slice_size)
# prints 3000

# setting a value initialization:
data = MapTOS4(mql.SlicedData(), file_slice_size=4000)
print(data.file_slice_size)
# prints 4000
  

Комментарии:

1. Большое спасибо @krassowski за ваш ответ, он работает, теперь я могу получить и установить атрибуты класса. Есть ли способ, которым я могу установить и получить атрибуты, не используя ‘get_r_attribute = ro.baseenv[‘$’] и set_r_attribute = ro.baseenv[‘$<-‘]?

2. Почему вам не нравятся get_r_attribute и set_r_attribute?

3. Мне это действительно нравится, но я хочу посмотреть, есть ли способ сделать его более питоническим?

4. Если бы мне нужно было что-то изменить, я бы сохранил get_r_attribute / set_r_attribute (они объясняют, что происходит), но поэкспериментировал с использованием __getattr__ и __setattr__ специальных методов для автоматизации процесса получения R свойств объекта; это потребовало бы дополнительной работы для свойств с точкой в имени. Не уверен, насколько это поможет.

5. Я понял, что ж, тогда я приму ваше предложение и сохраню их. Большое вам спасибо за ваш ответ, я проголосовал за thump up и приму ваш ответ.