#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 и приму ваш ответ.