R编程中的S3类
R 语言中的所有事物都被视为对象。对象具有属性,与对象相关的最常见的属性是类。命令类用于定义对象的类或了解对象的类。
类是一个向量,这个属性允许做两件事:
- 允许对象从多个类继承
- 可以为复杂类指定继承顺序
示例:检查对象的类
Python3
# Creating a vector x consisting of type of genders
x<-c("female", "male", "male", "female")
# Using the command class()
# to check the class of the vector
class(x)
Python3
# Creating a vector x consisting of type of genders
x<-c("female", "male", "male", "female")
# Using the command class()
# to append the class of the vector
class(x)<-append(class(x), "Gender")
class(x)
Python3
# Creating a vector x consisting of type of genders
# Creating a vector for age
age<-c(12, 10, 09)
# The command environment() can be used
# to bring the pointer to current environment
e <- environment()
e
# Setting the value of the variable
assign("age", 3, e)
ls()
# Getting the values of the variable
get("age", e)
Python3
x <- list(name ="Arjun", account_no = 1234,
saving = 1500, withdrawn = 234)
class(x)<-"bank"
x
Python3
x <- list(name ="Arjun", percentage = 95,
school_name ="ST Xavier")
class(x)<-"resume"
x
Python3
methods(print)
Python3
x <- list(name ="Arjun", account_no = 1234,
saving = 1500, withdrawn = 234)
class(x)<-"bank"
print.bank<-function(obj)
{
cat("Name is ", obj$name, "\n")
cat(obj$account_no, " is the Acc no of the holder\n ")
cat(obj$saving, " is the amount of saving in the account \n ")
cat(obj$withdrawn, " is the withdrawn amount\n")
}
x
Python3
# Defining a function
indian <- function(eatslunch = TRUE, myFavorite ="daal")
{
me <- list(haslunch = eatslunch,
favoritelunch = myFavorite)
# Set the name for the class
class(me) <- append(class(me), "indian")
return(me)
}
# Reserving the name of the function and
# by using the command UseMethod
# R will search for the appropriate function.
setHaslunch <- function(e, newValue)
{
print("Calling the base setHaslunch function")
UseMethod("setHaslunch", e)
print(" this is not executed")
}
setHaslunch.default <- function(e, newValue)
{
print("This objects is unable to be handled.")
return(e)
}
setHaslunch.indian <- function(e, newValue)
{
print("R is in setHaslunch.indian and is setting the value")
e$haslunch <- newValue
return(e)
}
# objects calling functions
foodie <- indian()
foodie$haslunch
foodie <- setHaslunch(foodie, FALSE)
foodie$haslunch
Python3
# Defining a function
x <- list(name ="Arjun", percentage = 95,
school_name ="ST Xavier")
attributes(x)
Python3
# Defining a function
x <- list(name ="Arju", percentage = 95,
school_name ="ST Xavie")
attr(x, "age")<-c(18)
attributes(x)
输出:
[1] "character"
示例:附加对象的类
Python3
# Creating a vector x consisting of type of genders
x<-c("female", "male", "male", "female")
# Using the command class()
# to append the class of the vector
class(x)<-append(class(x), "Gender")
class(x)
输出:
[1] "character" "Gender"
管理内存
在进行面向对象编程时,程序员可能会怀疑使用哪个类——S3 还是 S4?
在比较这两个类时,S4 具有更结构化的方法,而 S3 被认为是一个灵活的类。
内存环境负责 S3 类的灵活性。
环境就像一个本地范围,并且有一个与之关联的变量集。如果与环境关联的“ID”已知,则可以访问这些变量。
要了解或设置环境中变量的值,可以使用assign和get等命令。
示例:在环境中分配和获取变量的值
Python3
# Creating a vector x consisting of type of genders
# Creating a vector for age
age<-c(12, 10, 09)
# The command environment() can be used
# to bring the pointer to current environment
e <- environment()
e
# Setting the value of the variable
assign("age", 3, e)
ls()
# Getting the values of the variable
get("age", e)
输出:
[1] "age" "e" "x"
[1] 3
可以轻松创建环境。它们也可以嵌入到其他环境中。
创建 S3 类
S3 类是 R 编程中最流行和使用的类。这个类很容易实现,大多数预定义的类都是这种类型。
S3 对象基本上是一个列表,其类属性分配了一些名称。而创建的对象的成员变量就是列表的组成部分。
创建 S3 对象有两个主要步骤:
- 创建一个包含所需组件的列表(比如 x)
- 然后可以通过命令 class(x) 形成该类,并且应该为该类分配一个名称
示例:可以轻松创建银行帐户详细信息的 S3 对象。
Python3
x <- list(name ="Arjun", account_no = 1234,
saving = 1500, withdrawn = 234)
class(x)<-"bank"
x
Output:
$name
[1] "Arjun"
$account_no
[1] 1234
$saving
[1] 1500
$withdrawn
[1] 234
attr(, "class")
[1] "bank"
示例:可以轻松创建个人简历的 S3 对象。
Python3
x <- list(name ="Arjun", percentage = 95,
school_name ="ST Xavier")
class(x)<-"resume"
x
输出:
$name
[1] "Arjun"
$percentage
[1] 95
$school_name
[1] "ST Xavier"
attr(, "class")
[1] "resume"
其他语言(如Python、 Java、C++ 等)对类有适当的定义,并且对象具有适当定义的方法和属性。
但在S3类系统的R语言中,它是灵活的,你甚至可以修改或转换它们(同一个类的对象可以不同)。
R语言中的S3系统由三个主要部分组成
- 通用函数
- 方法
- 属性
通用函数
R 经常使用 print()函数。如果你输入类的名字,它的内部信息会被打印出来,或者你可以使用命令 print(name of the class)。但是相同的函数print() 用于打印不同的东西,比如向量、数据帧、矩阵等。
print() 如何识别这种不同的输入?
函数print() 是一个通用函数,因此是方法的集合。这些方法可以通过键入命令方法(打印)进一步检查。
Python3
methods(print)
输出:
[1] print.AES*
[2] print.Arima*
[3] print.AsIs
[4] print.Bibtex*
[5] print.CRAN_package_reverse_dependencies_and_views*
[6] print.DLLInfo
[7] print.DLLInfoList
[8] print.DLLRegisteredRoutines
[9] print.Date
[10] print.Dlist
[11] print.HoltWinters*
[12] print.LaTeX*
[13] print.Latex*
[14] print.MethodsFunction*
[15] print.NativeRoutineList
[16] print.PDF_Array*
[17] print.PDF_Dictionary*
[18] print.PDF_Indirect_Reference*
[19] print.PDF_Keyword*
[20] print.PDF_Name*
[21] print.PDF_Stream*
[22] print.PDF_String*
[23] print.POSIXct
[24] print.POSIXlt
[25] print.R6*
[26] print.R6ClassGenerator*
[27] print.RGBcolorConverter*
[28] print.Rcpp_stack_trace*
[29] print.Rd*
[30] print.SOCK0node*
[31] print.SOCKcluster*
[32] print.SOCKnode*
[33] print.State*
[34] print.StructTS*
[35] print.TukeyHSD*
[36] print.acf*
[37] print.anova*
[38] print.aov*
[39] print.aovlist*
[40] print.ar*
[41] print.arima0*
[42] print.aspell*
[43] print.aspell_inspect_context*
[44] print.bibentry*
[45] print.browseVignettes*
[46] print.by
[47] print.bytes*
[48] print.changedFiles*
[49] print.checkDocFiles*
[50] print.checkDocStyle*
[51] print.checkFF*
[52] print.checkRd*
[53] print.checkReplaceFuns*
[54] print.checkS3methods*
[55] print.checkTnF*
[56] print.checkVignettes*
[57] print.check_Rd_contents*
[58] print.check_Rd_line_widths*
[59] print.check_Rd_metadata*
[60] print.check_Rd_xrefs*
[61] print.check_RegSym_calls*
[62] print.check_T_and_F*
[63] print.check_code_usage_in_package*
[64] print.check_compiled_code*
[65] print.check_demo_index*
[66] print.check_depdef*
[67] print.check_details*
[68] print.check_details_changes*
[69] print.check_doi_db*
[70] print.check_dotInternal*
[71] print.check_make_vars*
[72] print.check_nonAPI_calls*
[73] print.check_package_CRAN_incoming*
[74] print.check_package_code_assign_to_globalenv*
[75] print.check_package_code_attach*
[76] print.check_package_code_data_into_globalenv*
[77] print.check_package_code_startup_functions*
[78] print.check_package_code_syntax*
[79] print.check_package_code_unload_functions*
[80] print.check_package_compact_datasets*
[81] print.check_package_datasets*
[82] print.check_package_depends*
[83] print.check_package_description*
[84] print.check_package_description_encoding*
[85] print.check_package_license*
[86] print.check_packages_in_dir*
[87] print.check_packages_used*
[88] print.check_po_files*
[89] print.check_so_symbols*
[90] print.check_url_db*
[91] print.check_vignette_index*
[92] print.citation*
[93] print.codoc*
[94] print.codocClasses*
[95] print.codocData*
[96] print.colorConverter*
[97] print.compactPDF*
[98] print.condition
[99] print.connection
[100] print.data.frame
[101] print.default
[102] print.dendrogram*
[103] print.density*
[104] print.difftime
[105] print.dist*
[106] print.dummy_coef*
[107] print.dummy_coef_list*
[108] print.ecdf*
[109] print.eigen
[110] print.factanal*
[111] print.factor
[112] print.family*
[113] print.fileSnapshot*
[114] print.findLineNumResult*
[115] print.formula*
[116] print.fseq*
[117] print.ftable*
[118] print.function
[119] print.getAnywhere*
[120] print.glm*
[121] print.hclust*
[122] print.help_files_with_topic*
[123] print.hexmode
[124] print.hsearch*
[125] print.hsearch_db*
[126] print.htest*
[127] print.html*
[128] print.html_dependency*
[129] print.htmlwidget*
[130] print.infl*
[131] print.integrate*
[132] print.isoreg*
[133] print.kmeans*
[134] print.libraryIQR
[135] print.listof
[136] print.lm*
[137] print.loadings*
[138] print.loess*
[139] print.logLik*
[140] print.ls_str*
[141] print.medpolish*
[142] print.mtable*
[143] print.news_db*
[144] print.nls*
[145] print.noquote
[146] print.numeric_version
[147] print.object_size*
[148] print.octmode
[149] print.packageDescription*
[150] print.packageIQR*
[151] print.packageInfo
[152] print.packageStatus*
[153] print.pairwise.htest*
[154] print.pdf_doc*
[155] print.pdf_fonts*
[156] print.pdf_info*
[157] print.person*
[158] print.power.htest*
[159] print.ppr*
[160] print.prcomp*
[161] print.princomp*
[162] print.proc_time
[163] print.raster*
[164] print.recordedplot*
[165] print.restart
[166] print.rle
[167] print.roman*
[168] print.sessionInfo*
[169] print.shiny.tag*
[170] print.shiny.tag.list*
[171] print.simple.list
[172] print.smooth.spline*
[173] print.socket*
[174] print.srcfile
[175] print.srcref
[176] print.stepfun*
[177] print.stl*
[178] print.subdir_tests*
[179] print.summarize_CRAN_check_status*
[180] print.summary.aov*
[181] print.summary.aovlist*
[182] print.summary.ecdf*
[183] print.summary.glm*
[184] print.summary.lm*
[185] print.summary.loess*
[186] print.summary.manova*
[187] print.summary.nls*
[188] print.summary.packageStatus*
[189] print.summary.ppr*
[190] print.summary.prcomp*
[191] print.summary.princomp*
[192] print.summary.table
[193] print.summaryDefault
[194] print.suppress_viewer*
[195] print.table
[196] print.tables_aov*
[197] print.terms*
[198] print.ts*
[199] print.tskernel*
[200] print.tukeyline*
[201] print.tukeysmooth*
[202] print.undoc*
[203] print.vignette*
[204] print.warnings
[205] print.xgettext*
[206] print.xngettext*
[207] print.xtabs*
在上面的长列表中,有一些重要的方法,比如 print.factor()。当我们通过函数print() 打印一个因子时,调用会自动调度到 print.factor()
创建为 -bank 的类将搜索名为 print.bank() 的方法,并且由于不存在此类方法,因此使用 print.default()。
泛型函数有一个默认方法,当没有匹配可用时使用该方法。
创建自己的方法
创建自己的方法是可能的。
现在如果类 - 'bank' 搜索 print.bank(),它会找到这个方法并使用它,如果我们已经创建了它。
Python3
x <- list(name ="Arjun", account_no = 1234,
saving = 1500, withdrawn = 234)
class(x)<-"bank"
print.bank<-function(obj)
{
cat("Name is ", obj$name, "\n")
cat(obj$account_no, " is the Acc no of the holder\n ")
cat(obj$saving, " is the amount of saving in the account \n ")
cat(obj$withdrawn, " is the withdrawn amount\n")
}
x
输出:
Name is Arjun
1234 is the Acc no of the holder
1500 is the amount of saving in the account
234 is the withdrawn amount
一般来说,现在可以轻松定义和理解创建方法。
- 首先定义一个存在于类之外的函数(以通用方式)。
- 其次,定义给定类的函数细节。
根据函数参数的类名和写在关联函数名称中的后缀,R 环境决定使用哪个函数。
Python3
# Defining a function
indian <- function(eatslunch = TRUE, myFavorite ="daal")
{
me <- list(haslunch = eatslunch,
favoritelunch = myFavorite)
# Set the name for the class
class(me) <- append(class(me), "indian")
return(me)
}
# Reserving the name of the function and
# by using the command UseMethod
# R will search for the appropriate function.
setHaslunch <- function(e, newValue)
{
print("Calling the base setHaslunch function")
UseMethod("setHaslunch", e)
print(" this is not executed")
}
setHaslunch.default <- function(e, newValue)
{
print("This objects is unable to be handled.")
return(e)
}
setHaslunch.indian <- function(e, newValue)
{
print("R is in setHaslunch.indian and is setting the value")
e$haslunch <- newValue
return(e)
}
# objects calling functions
foodie <- indian()
foodie$haslunch
foodie <- setHaslunch(foodie, FALSE)
foodie$haslunch
输出:
[1] TRUE
[1] "Calling the base setHaslunch function"
[1] "R is in setHaslunch.indian and is setting the value"
[1] FALSE
属性
对象的属性不影响对象的值,但它们是用于处理对象的一条额外信息。
函数attributes()可用于查看对象的属性。
示例:创建 S3 对象并显示其属性。
Python3
# Defining a function
x <- list(name ="Arjun", percentage = 95,
school_name ="ST Xavier")
attributes(x)
输出:
$names
[1] "name" "percentage" "school_name"
$class
[1] "resume"
此外,您可以使用 attr 向对象添加属性。
Python3
# Defining a function
x <- list(name ="Arju", percentage = 95,
school_name ="ST Xavie")
attr(x, "age")<-c(18)
attributes(x)
输出:
$names
[1] "name" "percentage" "school_name"
$age
[1] 18
S3 之所以如此命名,是因为它起源于 S 语言的第三版。 S 是一种编程语言,后来修改为 R 和 S plus。