经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » R语言 » 查看文章
R语言S3类的理解与构建
来源:cnblogs  作者:ywliao  时间:2018/9/25 20:20:51  对本文有异议

R语言类

R语言的类有S3类和S4类,S3类用的比较广,创建简单粗糙但是灵活,而S4类比较精细,具有跟C++一样严格的结构。这里我们主要讲S3类。

S3类的结构

S3类内部是一个list,append某个list类名称,就能成为该类。list里面的内容就是我们所说的属性.
首先创建一个list

  1. me <- list(seq = "ATGC", length = nchar("ATGC"))
  2. me
  3. $seq
  4. [1] "ATGC"
  5. $length
  6. [1] 4

现在me这个list只属于list类

  1. me
  2. $seq
  3. [1] "ATGC"
  4. $length
  5. [1] 4
  6. attr(,"class")
  7. [1] "list" "DNAseq"

然后我们append 一个类名"DNAseq",就这样我们创建了一个DNAseq类,类的属性有seq和length,值为ATGC和4

  1. class(me) <- append(class(me), "DNAseq")
  2. class(me)
  3. [1] "list" "DNAseq"

我们可以通过普通的list的方法来获得类的属性,比如

  1. me$seq
  2. [1] "ATGC"
  3. me$length
  4. [1] 4

S3类的创建

简单直接的构建方法

依据刚才的类的结构,我们用函数进行类的构建,函数的输入是要传入进行类的初始化的值,而函数的返回就是新生成的类。这样我们就可以根据不同的初始化值进行类的实例化。
首先构造一个类

  1. # Straight forward approach
  2. DNAseq <- function(seq = "ATGCATGCATGCATGCATGC"){
  3. me <- list(
  4. seq = seq,
  5. length = nchar(seq)
  6. )
  7. # Set the name for the class
  8. class(me) <- append(class(me), "DNAseq")
  9. return(me)
  10. }

类的实例

  1. seq1 <- DNAseq()
  2. seq1
  3. $seq
  4. [1] "ATGCATGCATGCATGCATGC"
  5. $length
  6. [1] 20
  7. attr(,"class")
  8. [1] "list" "DNAseq"

局部环境构建类的方法

当然本质还是list,但是巧妙的利用了函数运行时的局部环境。函数运行时,内部的环境是和外界隔离的,在函数内创建的变量不会影响函数外。而这种方法巧妙的取出了这个内部环境的指针,并且将它放到了list里面。最后append类名。在环境里面存放了list的指针,而在list里面又存放了环境的指针。之所以内部环境没有消失,我猜想是因为返回的类里面具有环境的指针的引用,所以内存没有释放,是一个智能指针,当然,我没有对这深究。这次属性并不是直接存放在list里面,而是存放在函数里面的环境中。而list里面放着:方法和当前环境的指针。assign是对环境中某个变量赋值,可以用get函数中获得环境中变量的值。

  1. # Local enviroment approach
  2. DNASeq <- function(seq = "ATGCATGCATGCATGCATGC"){
  3. ## Get the enviroment for this
  4. thisEnv <- environment()
  5. seq <- seq
  6. length <- nchar(seq)
  7. ## Create the list used to represent the
  8. ## object for this class
  9. me <- list(
  10. ## Define the enviroment where this list is defined so
  11. ## that I can refer to it
  12. thisEnv = thisEnv,
  13. ## Method to refer to the current enviroment
  14. getEnv = function(){
  15. return(get("thisEnv", thisEnv))
  16. }
  17. )
  18. ## Define the value of list within the
  19. ## current enviroment
  20. assign("this", me, envir = thisEnv)
  21. ##Set the name for the class
  22. class(me) <- append(class(me), "DNASeq")
  23. return(me)
  24. }

实例化

  1. seq2 <- DNASeq()
  2. seq2
  3. $thisEnv
  4. <environment: 0x8e86a20>
  5. $getEnv
  6. function ()
  7. {
  8. return(get("thisEnv", thisEnv))
  9. }
  10. <environment: 0x8e86a20>
  11. $getseq
  12. function ()
  13. {
  14. return(get("seq", thisEnv))
  15. }
  16. <environment: 0x8e86a20>
  17. $reverseComplement
  18. function ()
  19. {
  20. print("Calling the reverseComplement function of DNASeq class")
  21. to_base <- c("A", "T", "G", "C")
  22. names(to_base) <- c("T", "A", "C", "G")
  23. trans_seq_vect <- to_base[unlist(strsplit(get("seq", thisEnv),
  24. split = ""))]
  25. trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1]
  26. newseq <- paste0(trans_rev_vect, collapse = "")
  27. return(DNASeq(newseq))
  28. }
  29. <environment: 0x8e86a20>
  30. attr(,"class")
  31. [1] "list" "DNASeq"

获得里面的seq属性的值,这里使用get获得环境中的变量的值

  1. get("seq", seq2$getEnv())
  2. [1] "ATGCATGCATGCATGCATGC"

当然,如果使用这种方法生成的类,我们获得属性通常不再函数外用get,因为这样并不像面向对象的用法,我们会在给类一个方法,某个类调用这个方法之后就可以获得某个属性的值,比如可以在list中再写一个函数,getseq,就等于get("seq", thisEnv),这样就可以面向对象的使用seq2$getseq()来获得seq属性。当我们列表中添加方法时,注意应该用遵循列表的格式,用",”分开不同的方法或者不同的值。

创建方法

类中除了含有属性外,肯定还得含有方法。上面我们讲到用局部环境变量创建S3类时可以在list里面存放方法。当然还有一种比较普遍的,在两种方式创建的S3类中都能使用的创建方法的途径。使用某方法.某类来创建某类的方法。比如print.gg就是对gg类的print的方法。但是在创建这种方法之前我们首先得用这个方法的名字创建一个函数,这样运行函数时首先进入这个函数,然后在函数里面使用useMethod函数,在环境中寻找该类的该方法。虽然下面的代码比较复杂,但是重点时看UseMethod。

  1. # Creating methods
  2. reverseComplement <- function(object){
  3. UseMethod("reverseComplement", object)
  4. }
  5. reverseComplement.default <- function(object){
  6. print("The class of this object can not be found")
  7. }
  8. # Straight forward approach
  9. #
  10. # For S3 classes created by Straight forward approach
  11. reverseComplement.DNAseq <- function(object){
  12. print("Calling the reverseComplement function of DNAseq class")
  13. ## Compelement according to the vector below
  14. to_base <- c("A", "T", "G", "C")
  15. names(to_base) <- c("T", "A", "C", "G")
  16. ## Transform long charactor to vector and complement
  17. trans_seq_vect <- to_base[unlist(strsplit(object$seq, split = ""))]
  18. ## Reverse
  19. trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1]
  20. ## Collape to long character
  21. newseq <- paste0(trans_rev_vect, collapse = "")
  22. # Return a new DNAseq class
  23. return(DNAseq(newseq))
  24. }
  25. # For S3 classed created by local enviroment approach
  26. reverseComplement.DNASeq <- function(object){
  27. print("Calling the reverseComplement function of DNASeq class")
  28. ## Compelement according to the vector below
  29. to_base <- c("A", "T", "G", "C")
  30. names(to_base) <- c("T", "A", "C", "G")
  31. ## Transform long charactor to vector and complement
  32. trans_seq_vect <- to_base[unlist(strsplit(get("seq", seq2$getEnv()), split = ""))]
  33. ## Reverse
  34. trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1]
  35. ## Collape to long character
  36. newseq <- paste0(trans_rev_vect, collapse = "")
  37. # Return a new DNASeq class
  38. return(DNASeq(newseq))
  39. }

上面还有一个default函数,表示默认的方法,如果该类找不到该类匹配的方法,就会使用默认方法。

类继承

S3类可以使用继承,在原来类的基础上再append一个新的类名即为新的类,用NextMethod可以调用下一层类的方法。
创建一个primer类继承DNAseq类

  1. #inheritance
  2. Primer <- function(seq = "ATGCATGCATGCATGCATGCGGCC"){
  3. pr <- strtrim(seq, 20)
  4. me <- DNAseq(pr)
  5. class(me) <- append(class(me), "Primer")
  6. return(me)
  7. }
  8. Primer1 <- Primer()
  9. Primer1
  10. $seq
  11. [1] "ATGCATGCATGCATGCATGC"
  12. $length
  13. [1] 20
  14. attr(,"class")
  15. [1] "list" "DNAseq" "Primer"

调用方法的时候会按照从左到右的顺序,再这个例子中,默认先调用DNAseq的方法,如果想要调用Primer类的方法,首先写一个Primer的reverseComplement方法

  1. # Creating methods
  2. reverseComplement.Primer <- function(object){
  3. print("Running reverseComplement of Primer class")
  4. }

然后在DNAseq类中调用下一类的方法,使用NextMethod

  1. reverseComplement.DNAseq <- function(object){
  2. print("Calling the reverseComplement function of DNAseq class")
  3. NextMethod("reverseComplement", object)
  4. ## Compelement according to the vector below
  5. to_base <- c("A", "T", "G", "C")
  6. names(to_base) <- c("T", "A", "C", "G")
  7. ## Transform long charactor to vector and complement
  8. trans_seq_vect <- to_base[unlist(strsplit(object$seq, split = ""))]
  9. ## Reverse
  10. trans_rev_vect <- trans_seq_vect[length(trans_seq_vect):1]
  11. ## Collape to long character
  12. newseq <- paste0(trans_rev_vect, collapse = "")
  13. # Return a new DNAseq class
  14. return(DNAseq(newseq))
  15. }
  1. reverseComplement(Primer1)
  2. [1] "Calling the reverseComplement function of DNAseq class"
  3. [1] "Running reverseComplement of Primer class"
  4. $seq
  5. [1] "GCATGCATGCATGCATGCAT"
  6. $length
  7. [1] 20
  8. attr(,"class")
  9. [1] "list" "DNAseq"
  1. reverseComplement(seq1)
  2. [1] "Calling the reverseComplement function of DNAseq class"
  3. [1] "The class of this object can not be found"
  4. $seq
  5. [1] "GCATGCATGCATGCATGCAT"
  6. $length
  7. [1] 20
  8. attr(,"class")
  9. [1] "list" "DNAseq"
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号