问题
I have made the following S4 class in R, its constructor takes a variable called 'A', which is a string. The class has a method called 'test_method', which takes as input a string 'B' and returns whether 'A' equals 'B'.
test_class <- setRefClass(
"test_class",
fields=list(A="character"),
methods = list(
test_method = function(B) {
if (A==B) {
return('yes')
} else {
return('no')
}
}
)
)
Now, I can make an instance of this class and execute 'test_method' on it:
object <- test_class(A='hello')
object$test_method('hi')
This returns 'no', because the strings do not equal.
Now I want to save this object I have made and execute 'test_method' from Python. I make an RDS:
saveRDS(object, 'object.rds')
Now I know how to read this object into Python using rpy2 (however I don't really care which package to use, as it works):
from rpy2.robjects import R
r = R()
r_object = r.readRDS("object.rds")
But how can I execute 'test_method' now? I tried this, but it doesn't work:
r_object.test_method('hi')
This throws: "AttributeError: 'RS4' object has no attribute 'test_method'"
回答1:
The rpy2 documentation about S4 classes does not cover well reference classes mostly because the rpy2
code predates the reference classes extension to S4.
In short, the S4 reference classes are not mapped to Python attributes, but writing a child Python class that does it is relatively easy.
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')
We have a rather generic S4 object:
>>> type(s4obj)
rpy2.robjects.methods.RS4
Writing a child class that inherits from that generic class can look like this:
class TestClass(ro.methods.RS4):
def test_method(self, b):
return ro.baseenv['$'](self, 'test_method')(b)
Casting is straightforward and computationally cheap (the parent class's constructor will just pass through an R object that is already an S4 object):
s4testobj = TestClass(s4obj)
Now we can do:
>>> tuple(s4testobj.test_method('hi'))
('no',)
For additional automagical creation of methods and attributes in Python from the R class definition, and conversion to the custom child, you'll need to use metaprogramming on the Python side, and define custom conversion (there is a link to the latter in the link to the documentation provided earlier).
Note: If not tied to S4 Reference Classes, the R6 class system for R is worth a look. An rpy2
's mapping for that class system is here: https://github.com/rpy2/rpy2-R6.
来源:https://stackoverflow.com/questions/63069677/how-to-execute-s4-class-method-in-python-using-rpy2