如何在 Python 中执行 S4 class 方法(使用 rpy2)?

How to execute S4 class method in Python (using rpy2)?

我在R中做了下面的S4 class,它的构造函数接受一个名为'A'的变量,它是一个字符串。 class 有一个名为 'test_method' 的方法,它将字符串 'B' 和 returns 作为输入,无论 'A' 是否等于 'B'.

test_class <- setRefClass(
  "test_class",
  fields=list(A="character"),
  methods = list(
    test_method = function(B) {
       if (A==B) {
           return('yes')
       } else {
           return('no')
       }
    }
  )
)

现在,我可以创建此 class 的实例并在其上执行 'test_method':

object <- test_class(A='hello')
object$test_method('hi')

这个returns'no',因为字符串不相等

现在我想保存我制作的这个对象并从Python执行'test_method'。我做了一个 RDS:

saveRDS(object, 'object.rds')

现在我知道如何使用 rpy2 将此对象读入 Python(但是我真的不关心使用哪个包,因为它有效):

from rpy2.robjects import R
r = R()
r_object = r.readRDS("object.rds")

但是我现在如何执行'test_method'呢?我试过这个,但它不起作用:

r_object.test_method('hi')

这会抛出:“AttributeError:'RS4' 对象没有属性 'test_method'”

rpy2 documentation about S4 classes 没有很好地涵盖参考 classes,主要是因为 rpy2 代码早于参考 classes 对 S4 的扩展。

简而言之,S4 引用 classes 没有映射到 Python 属性,但是写一个子 Python class 是相对容易的。

import rpy2.robjects as ro
test_class = ro.r("""
  setRefClass(
    "test_class",
    fields=list(A="character"),
    methods = list(
      test_method = function(B) {
         if (A==B) {
             return('yes')
         } else {
             return('no')
         }
      }
    )
  )
""")
s4obj = test_class(A='hello')

我们有一个相当通用的 S4 对象:

>>> type(s4obj)
rpy2.robjects.methods.RS4

编写一个继承自泛型 class 的子 class 可以如下所示:

class TestClass(ro.methods.RS4): 
    def test_method(self, b): 
        return ro.baseenv['$'](self, 'test_method')(b) 

转换简单且计算成本低(父 class 的构造函数将只传递已经是 S4 对象的 R 对象):

s4testobj = TestClass(s4obj)

现在我们可以做:

>>> tuple(s4testobj.test_method('hi'))  
 ('no',)                                         

要从 R class 定义中自动创建 Python 中的方法和属性,并转换为自定义子项,您需要在 Python 上使用元编程侧,并定义自定义转换(在 link 之前提供的文档中有一个 link 到后者。

注意:如果不依赖于 S4 参考 类,R 的 R6 class 系统值得一看。 rpy2 对 class 系统的映射在这里:https://github.com/rpy2/rpy2-R6.