许多R功能以特殊方式返回将对象打印到控制台的对象。例如, t_results = t.t.test(c(1,2,3),c(1,2,4))
将把 list
分配给 t_results
变量,但是当我在控制台中输入此变量,或称其为 print(t_results)
或 show(t_results)
,它会打印一些普通文本信息(例如 welch两个示例t检验...
等),而不是返回实际的 list
。 (这是一个基本r函数,但我也看到了许多自定义用户r软件包中实现的。)
我的问题是:我该如何处理我自己的自定义R软件包中创建的对象?我已经阅读了几个相关的问题和答案(例如, this , this 和 this ),哪个确实给出了一个一般的想法(使用 setMethod
我的自定义类),但没有一个使我明确我需要什么以自定义的R软件包使其正常工作。我也找不到有关此事的任何官方文件或教程。
为了举一个我想做的示例,这是我的假设R软件包中的一个非常简单的功能,该功能只需返回一个小 data.frame
(我添加了任意类名称, 'my_df_class'
):
my_main_function = function() {
my_df = data.frame(a = c('x1', 'y2', 'z2'),
b = c('x2', 'y2', 'z2'))
class(my_df) = c(class(my_df), 'my_df_class')
return(my_df)
}
我想打印/显示的(例如
my_print_function = function(df) {
cat('My results:', df$a[2], df$a[3])
}
# see my_print_function(my_main_function())
:将 my_main_function()
分配给变量, print
s/ show
show s show 该变量,它将通过 my_print_function( )
)?
Many R functions return objects that are printed to the console in a special manner. For instance, t_results = t.test(c(1,2,3), c(1,2,4))
will assign a list
to the t_results
variable, but when I enter this variable in the console, or call it as print(t_results)
or show(t_results)
, it prints some plain text information (such as Welch Two Sample t-test...
etc.) instead of returning the actual list
. (This is a base R function, but I've seen this implemented in many custom user R packages just as well.)
My question is: how do I do this for objects created in my own custom R package? I've read several related questions and answers (e.g., this, this, and this), which do give a general idea (using setMethod
for my custom classes), but none of them makes it clear to me what exactly I need to do to make it work properly in a custom R package. I also cannot find any official documentation or tutorial on the matter.
To give an example of what I want to do, here is a very simple function from my hypothetical R package, which simply return a small data.frame
(with an arbitrary class name I add to it, here 'my_df_class'
):
my_main_function = function() {
my_df = data.frame(a = c('x1', 'y2', 'z2'),
b = c('x2', 'y2', 'z2'))
class(my_df) = c(class(my_df), 'my_df_class')
return(my_df)
}
I would like to have this printed/shown e.g. like this:
my_print_function = function(df) {
cat('My results:', df$a[2], df$a[3])
}
# see my_print_function(my_main_function())
What exactly has to be done to make this work for my R package (i.e., that when someone installs my R package, assigns the my_main_function()
results to a variable, and print
s/show
s that variable, it would be done via my_print_function()
)?
发布评论
评论(2)
这是一个小解释。添加@NYA发布的惊人答案:
首先,您正在处理S3课程。有了这些类,我们可以使用一种方法来操纵对象,具体取决于对象所属的类。
下面是一个简单的类及其运作方式:
- 让我们调用类
my_numbers
现在我们将定义类构造函数:
请注意,我们添加了类“数字”。即类
my_numbers
从数字类继承我们可以创建上述类的对象,如下所示:
没有什么特别的。仅将类的属性添加到向量。 来轻松删除/剥离属性
您可以通过调用
c(b)
vectorb
。请注意,
class
属性可以由以下任何一个添加(其他许多方法):魔术在哪里?
我将用递归写一个简单的功能。不必担心功能实现。我们将以它为例。
仍然没有魔法。多数民众赞成在
b
上称为正常功能。而不是调用函数
my_numbers_print
我们可以用名称print.my_numbers
iemethod.class_name
(注意我添加了parametermethod> method> method> print.my_numbers
IE ie ie ie> quote = false
,我们仍然可以在b上
添加数学
现在 功能。
另一个
因为我们需要更改
Here is a small explanation. Adding to the amazing answer posted by @nya:
First, you are dealing with S3 classes. With these classes, we can have one method manipulating the objects differently depending on the class the object belongs to.
Below is a simple class and how it operates:
-- Lets call the class
my_numbers
Now we will define the class constructor:
Note that we added the class 'numeric'. ie the class
my_numbers
INHERITS from numeric classWe can create an object of the said class as follows:
Nothing special has happened. Only an attribute of class has been added to the vector. You can easily remove/strip off the attribute by calling
c(b)
vector
b
is just a normal vector of numbers.Note that the
class
attribute could have been added by any of the following (any many more ways):Where is the magic?
I will write a simple function with recursion. Don't worry about the function implementation. We will just use it as an example.
There is no magic still. Thats the normal function called on
b
.Instead of calling the function
my_numbers_print
we could write another function with the nameprint.my_numbers
iemethod.class_name
(Note I added the parameterquote = FALSE
Now b has been printed nicely. We can still do math on b
Can we add b to a dataframe?
b
reverts back to numeric instead of maintaining its class. That is because we need to change another function. ie theformats
function.Ideally, the correct way to do this is to create a format function and then the print function. (Becoming too long)
Summary : Everything Put Together
使用特定功能的最简单方法是将其设置为S3通用。
请注意,由于您保留
data.frame
lineclass(my_df)= c(class(my_df),'my_df_class')
,print()
将显示data.frame的打印。您可以使用
print.my_df_class()
,也可以修改my_main_function()
类分配。然后,您可以使用
print
,而无需在末尾进行类规范,以获得特定于类的响应。The easiest way to use a specific function for a class is to set it as an S3 generic.
Note that because you retain the
data.frame
class on lineclass(my_df) = c(class(my_df), 'my_df_class')
, theprint()
will show the printing of the data.frame.You can either use
print.my_df_class()
, or modify themy_main_function()
class assignment.Then you can use
print
without the class specification at the end to get a class-specific response.