数据处理利器python与scala面向对象对比分析2-大数据ML样本集案例实战

栏目: Python · 发布时间: 5年前

内容简介:版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。通过Python技术栈与Spark大数据数据平台整合,必然需要本文进行详细对比,粗陋成文,在于作者复习,勿怪。秦凯新 于深圳 201812132319

版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

1 python 与scala面向对象对比分析

1.1 scala面向对象

  • 定义类,包含field以及方法

    class HelloWorld {
        private var name = "leo"
        def sayHello() { print("Hello, " + name) }  
        def getName = name
      }
    
      创建类的对象,并调用其方法
      val helloWorld = new HelloWorld
      
      helloWorld.sayHello() 
      print(helloWorld.getName())  也可以不加括号,如果定义方法时不带括号,则调用方法时也不能带括号
      print(helloWorld.getName) 
    复制代码
  • scala自动生成getter与setter

    1 定义不带private的var field,此时scala生成的面向JVM的类时,
      会定义为private的name字段,并提供public的getter和setter方法
      
      2 而如果使用private修饰field,则生成的getter和setter也是private的
      
      3 如果定义val field,则只会生成getter方法
      
      4 如果不希望生成setter和getter方法,则将field声明为private[this]
      
      class Student {
        var name = "leo"
      }
      
      调用getter和setter方法,分别叫做name和name_ =
      val leo = new Student
      get方法
      print(leo.name)
      
      set方法1
      leo.name = "leo1"
      
      set方法2
      scala> leo.name_=("leo2")
      scala> leo.name
      res3: String = leo2
    复制代码
  • 自定义getter与setter方法

    如果只是希望拥有简单的getter和setter方法,那么就按照scala提供的语法规则,根据需求为field选择合适的修饰符就好:var、val、private、private[this]
      
      但是如果希望能够自己对getter与setter进行控制,则可以自定义getter与setter方法
      自定义setter方法的时候一定要注意scala的语法限制,签名、=、参数间不能有空格
    
     虽然设置私有private,单提供了公共的set和get方法,可以对外访问
      class Student {
        private var myName = "leo"
        def name = "your name is " + myName
        def name_=(newValue: String)  {
          print("you cannot edit your name!!!")
        }
      }
      
      scala>   val leo = new Student
      leo: Student = Student@e36bc01
      
      scala> print(leo.name)
      your name is leo
      scala> leo.name = "leo1"
      you cannot edit your name!!!leo.name: String = your name is leo
      
      一旦设置私有private,则对外将不可以访问
       class Student {
        private var myName = "leo"
      }
      
      scala> ss.name
      <console>:26: error: value name is not a member of Student
             ss.name
                ^
      
      scala> ss.name_="asd"
      <console>:1: error: identifier expected but string literal found.
      ss.name_="asd"
    复制代码
  • Java风格的getter和setter方法

    Scala的getter和setter方法的命名与 java 是不同的,是field和field_=的方式
      如果要让scala自动生成java风格的getter和setter方法,只要给field添加@BeanProperty注解即可
      此时会生成4个方法,
      name: String、
      name_=(newValue: String): Unit
      
      getName():String、
      setName(newValue: String): Unit
      
      import scala.reflect.BeanProperty
      class Student {
        @BeanProperty var name: String = _
      }
      
      class Student(@BeanProperty var name: String)
      
      val s = new Student
      s.setName("leo")
      s.getName()
    复制代码
  • 辅助constructor

    Scala中,可以给类定义多个辅助constructor,类似于java中的构造函数重载
      辅助constructor之间可以互相调用,而且必须第一行调用主constructor
      
      class Student {
        private var name = ""
        private var age = 0
        
        def this(name: String) {
          this()
          this.name = name
        }
        def this(name: String, age: Int) {
          this(name)
          this.age = age
        }
      }
    复制代码
  • 主constructor(除了方法体内的代码都会执行)

    Scala中,主constructor是与类名放在一起的,与java不同
      而且类中,没有定义在任何方法或者是代码块之中的代码,就是主constructor的代码,这点感觉没有java那么清晰
      
      class Student(val name: String, val age: Int) {
        println("your name is " + name + ", your age is " + age)
      }
      
      主constructor中还可以通过使用默认参数,来给参数默认的值
      class Student(val name: String = "leo", val age: Int = 30) {
        println("your name is " + name + ", your age is " + age)
      }
      
      如果主constrcutor传入的参数什么修饰都没有,比如name:
      String,那么如果类内部的方法使用到了,则会声明为private[this]
      name;否则没有该field,就只能被constructor代码使用而已
    复制代码
  • 伴生对象

    1 如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象
      ,class是object的伴生类
      2 伴生类和伴生对象必须存放在一个.scala文件之中
      3 伴生类和伴生对象,最大的特点就在于,互相可以访问private field
      
      object Person {
        private val eyeNum = 2
        def getEyeNum = eyeNum
      }
      
      class Person(val name: String, val age: Int) {
        def sayHello = println("Hi, " + name + ", I guess you are " + age + " years old!" + ", and usually you must have " + Person.eyeNum + " eyes.")
      }
      
      scala> val s =new Person("leo",12)
      s: Person = Person@4d0abb23
      
      scala> s.sayHello
      Hi, leo, I guess you are 12 years old!, and usually you must have 2 eyes.
    复制代码
  • apply方法

    1 object中非常重要的一个特殊方法,就是apply方法,在创建伴生类的对象时,通常不会使用new Class的方式,而是使用Class()的方式,隐式地调用伴生对象得apply方法,这样会让对象创建更加简洁
      
      比如,Array类的伴生对象的apply方法就实现了接收可变数量的参数,并创建一个Array对象的功能
      val a = Array(1, 2, 3, 4, 5)
    
      2 定义自己的伴生类和伴生对象,省略掉new操作
      class Person(val name: String)
      object Person {
        def apply(name: String) = new Person(name)
      }
      scala> Person("xin")
      res7: Person = Person@484a5ddd  
    复制代码
  • main方法

    scala中的main方法定义为def main(args: Array[String]),而且必须定义在object中
    
      除了自己实现main方法之外,还可以继承App Trait,然后将需要在main方法中运行的代码,直接作为object的constructor代码;而且用args可以接受传入的参数
      
      object HelloWorld extends App {
        if (args.length > 0) println("hello, " + args(0))
        else println("Hello World!!!")
      }
    复制代码
  • extends

    子类可以覆盖父类的field和method;但是如果父类用final修饰,field和method用final修
      饰,则该类是无法被继承的,field和method是无法被覆盖的
      
      class Person {
        private var name = "leo"
        def getName = name
      }
      class Student extends Person {
        private var score = "A"
        def getScore = score
      }
    复制代码
  • override和super

    Scala中,如果子类要覆盖一个父类中的非抽象方法,则必须使用override关键字,在子类覆
      盖父类方法之后,如果我们在子类中就是要调用父类的被覆盖的方法呢?那就可以使用super
      关键字,显式地指定要调用父类的方法
      
      class Person {
        private var name = "leo"
        def getName = name
      }
      class Student extends Person {
        private var score = "A"
        def getScore = score
        override def getName = "Hi, I'm " + super.getName
      }
    复制代码
  • 类判别

    class Person
      class Student extends Person
      
      scala> val p: Person = new Student
      p: Person = Student@683fac7e
      
      scala> p.isInstanceOf[Person]
      res10: Boolean = true
      
      scala> p.getClass == classOf[Person]
      res11: Boolean = false
      
      scala> p.getClass == classOf[Student]
      res12: Boolean = true
    复制代码
  • 使用模式匹配进行类型判断

    使用模式匹配,功能性上来说,与isInstanceOf一样,也是判断主要是该类以及该类的子类
      的对象即可,不是精准判断的
      
      class Person
      class Student extends Person
      val p: Person = new Student
      
      scala> p match {
       |           case per: Person => println("it's Person's object")
       |           case _  => println("unknown type")
       |         }
       it's Person's object
    复制代码
  • 调用父类的constructor

    1 Scala中,每个类可以有一个主constructor和任意多个辅助constructor,而每个辅助constructor的第一行都必须是调用其他辅助constructor或者是主constructor;因此子类的辅助constructor是一定不可能直接调用父类的constructor的
      
      2 只能在子类的主constructor中调用父类的constructor,以下这种语法,就是通过子类的主构造函数来调用父类的构造函数
      
     3  注意!如果是父类中接收的参数,比如name和age,子类中接收时,就不要用任何val或var来修饰了,否则会认为是子类要覆盖父类的field
     
      class Person(val name: String, val age: Int)
      class Student(name: String, age: Int, var score: Double) extends Person(name, age) {
        def this(name: String) {
          this(name, 0, 0)
        }
        def this(age: Int) {
          this("leo", age, 0)
        }
      }
    复制代码
  • 将trait作为接口使用

    Scala中的Triat是一种特殊的概念
     首先我们可以将Trait作为接口来使用,此时的Triat就与Java中的接口非常类似
     在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
     
     类可以使用extends关键字继承trait,注意,这里不是implement,而是extends,在scala中没有implement的概念,无论继承类还是trait,统一都是extends
     
     类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
     scala不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可
     
     trait HelloTrait {
       def sayHello(name: String)
     }
     trait MakeFriendsTrait {
       def makeFriends(p: Person)
     }
     class Person(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable {
       def sayHello(name: String) = println("Hello, " + name)
       def makeFriends(p: Person) = println("Hello, my name is " + name + ", your name is " + p.name)
     }
    复制代码
  • 在Trait中定义具体字段

    Scala中的Triat可以定义具体field,此时继承trait的类就自动获得了trait中定义的field
     但是这种获取field的方式与继承class是不同的:如果是继承class获取的field,实际是定
     义在父类中的;而继承trait获取的field,就直接被添加到了类中。
     
     trait Person {
       val eyeNum: Int = 2
     }
     
     class Student(val name: String) extends Person {
       def sayHello = println("Hi, I'm " + name + ", I have " + eyeNum + " eyes.")
     }
    复制代码
  • 在Trait中定义抽象字段

    // Scala中的Triat可以定义抽象field,而trait中的具体方法则可以基于抽象field来编写
      // 但是继承trait的类,则必须覆盖抽象field,提供具体的值
      
      trait SayHello {
        val msg: String
        def sayHello(name: String) = println(msg + ", " + name)
      }
      
      class Person(val name: String) extends SayHello {
        val msg: String = "hello"
        def makeFriends(p: Person) {
          sayHello(p.name)
          println("I'm " + name + ", I want to make friends with you!")
        }
      }
    复制代码
  • 为实例混入trait(如果不使用With,trait方法不会执行)

    trait Logged {
        def log(msg: String) {}
      }
      trait MyLogger extends Logged {
        override def log(msg: String) { println("log: " + msg) }
      }  
      class Person(val name: String) extends Logged {
          def sayHello { println("Hi, I'm " + name); 
          log("sayHello is invoked!") }
      }
      
      val p1 = new Person("leo")
      p1.sayHello
      val p2 = new Person("jack") with MyLogger
      p2.sayHello
      
      scala> val p1 = new Person("leo")
      p1: Person = Person@75b3ef1a
      
      scala> p1.sayHello
      Hi, I'm leo
      
      scala> val p2 = new Person("jack") with MyLogger
      p2: Person with MyLogger = $anon$1@703eead0
      
      scala> p2.sayHello
      Hi, I'm jack
      log: sayHello is invoked!
    复制代码
  • trait调用链

    Scala中支持让类继承多个trait后,依次调用多个trait中的同一个方法,只要让多个trait的同一个方法中,在最后都执行super.方法即可。
     
     类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条
     
     这种特性非常强大,其实就相当于 设计模式 中的责任链模式的一种具体实现依赖
     
     trait Handler {
       def handle(data: String) {}
     }
     
     trait DataValidHandler2 extends Handler {
       override def handle(data: String) {
         println("check data2: " + data)
         super.handle(data)
       } 
     }
     
     
     trait DataValidHandler1 extends Handler {
       override def handle(data: String) {
         println("check data1: " + data)
         super.handle(data)
       } 
     }
     trait SignatureValidHandler extends Handler {
       override def handle(data: String) {
         println("check signature: " + data)
         super.handle(data)
       }
     }
     class Person(val name: String) extends SignatureValidHandler with DataValidHandler1 with DataValidHandler2 {
       def sayHello = { println("Hello, " + name); handle(name) }
     }
     
     scala> val p = new Person("person")
     p: Person = Person@7a85454b
     
     scala> p.sayHello
     Hello, person
     check data2: person
     check data1: person
     check signature: person
    复制代码
  • 在trait中覆盖抽象方法

    在trait中,是可以覆盖父trait的抽象方法的
     但是覆盖时,如果使用了super.方法的代码,则无法通过编译。因为super.方法就会去掉用父trait的抽象方法,此时子trait的该方法还是会被认为是抽象的
     此时如果要通过编译,就得给子trait的方法加上abstract override修饰
     
     trait Logger {
       def log(msg: String)
     }
     
     trait MyLogger extends Logger {
       abstract override def log(msg: String) { super.log(msg) }
     }
    复制代码
  • trait的构造机制(从左到右执行)

    class Person { println("Person's constructor!") }
     trait Logger { println("Logger's constructor!") }
     trait MyLogger extends Logger { println("MyLogger's constructor!") }
     trait TimeLogger extends Logger { println("TimeLogger's constructor!") }
     
     class Student extends Person with MyLogger with TimeLogger {
       println("Student's constructor!")
     }
     
     scala> val s = new Student
     Person's constructor!
     Logger's constructor!
     MyLogger's constructor!
     TimeLogger's constructor!
     Student's constructor!
     s: Student = Student@34a99d8
    复制代码

1.2 python面向对象

  • 定义类并创建实例

    按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。
     class Person(object):
         pass
    
     省掉new创建实例
     xiaoming = Person()
     xiaohong = Person()
    复制代码
  • 由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,临时追加属性

    xiaoming = Person()
     xiaoming.name = 'Xiao Ming'
     xiaoming.gender = 'Male'
     xiaoming.birth = '1990-1-1'
     
     print(xiaoming.name)
     Xiao Ming
    
     xiaohong.grade = xiaohong.grade + 1
    复制代码
  • 初始化实例属性

    init() 方法的第一个参数必须是self(也可以用别的名字,但建议使用习惯用法),
     后续参数则可以自由指定,和定义函数没有任何区别,相应地,创建实例时,就必须要提供除
     self 以外的参数
     
      class Person(object):
          def __init__(self, name, gender, birth):
              self.name = name
              self.gender = gender
              self.birth = birth
              
      xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
      xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')
      
      print (xiaoming.name)
      Xiao Ming
    复制代码
  • 实例属性访问限制

    Python对属性权限的控制是通过属性名来实现的,如果一个属性由双下划线开头(__),
      该属性就无法被外部访问
      
      class Person(object):
          def __init__(self, name):
              self.name = name
              self._title = 'Mr'
              self.__job = 'Student'
              
      p = Person('Bob')
      print p.name
      # => Bob
      print(p._title)
      # => Mr
      print p.__job
      
      ---------------------------------------------------------------------------
      AttributeError                            Traceback (most recent call last)
      <ipython-input-28-13a5b5479af8> in <module>()
      ----> 1 print(p.__job)
      
      AttributeError: 'Person' object has no attribute '__job'
    复制代码
  • 创建类属性

    类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性
      class Person(object):
          address = 'Earth'
          def __init__(self, name):
              self.name = name
      
      print (Person.address)
      Earth
      
      p1 = Person('Bob')
      p2 = Person('Alice')
      print p1.address
      # => Earth
      print p2.address
      # => Earth
      
      由于Python是动态语言,类属性也是可以动态添加和修改的
      Person.address = 'China'
      print p1.address
      # => 'China'
      print p2.address
      # => 'China'
      
      类属性和实例实型名字冲突怎么办?当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
      class Person(object):
          address = 'Earth'
          def __init__(self, name):
              self.name = name
    
      p1 = Person('Bob')
      p2 = Person('Alice')
      
      print 'Person.address = ' + Person.address
      
      p1.address = 'China'
      print ('p1.address = ' + p1.address)
      p1.address = China
    
      print ('p2.address = ' + p2.address)
      p2.address = Earth
    复制代码
  • 定义实例方法

    一个实例的私有属性就是以__开头的属性,无法被外部访问,实例的方法就是在类中定义的
      函数,它的第一个参数永远是 self,虽然name是私有的不能被访问,
      但是get_name就可以被访问。
      
      class Person(object):
      
          def __init__(self, name):
              self.__name = name
      
          def get_name(self):
              return self.__name
    
      p1 = Person('Bob')
      print(p1.get_name())
      Bob
    复制代码
  • 把方法追加到类上

    import types
    
      def fn_get_grade(self):
          if self.score >= 80:
              return 'A'
          if self.score >= 60:
              return 'B'
          return 'C'
      
      class Person(object):
          def __init__(self, name, score):
              self.name = name
              self.score = score
      
      p1 = Person('Bob', 90)
      p1.get_grade = types.MethodType(fn_get_grade, p1)
      print (p1.get_grade())
    
      A
    复制代码
  • 定义类方法

    class Person(object):
         count = 0
         @classmethod
         def how_many(cls):
             return cls.count
         def __init__(self, name):
             self.name = name
             Person.count = Person.count + 1
             
    print(Person.how_many())
    0
    
    p1 = Person('Bob')
    print(Person.how_many())
    3
    复制代码
  • 继承一个类

    class Person(object):
      def __init__(self, name, gender):
          self.name = name
          self.gender = gender
    
    class Student(Person):
          def __init__(self, name, gender, score):
              super(Student, self).__init__(name, gender)
              self.score = score
    
    class Teacher(Person):
      def __init__(self, name, gender, course):
          super(Teacher, self).__init__(name, gender)
          self.course = course  
      
     p = Person('Tim', 'Male')
     s = Student('Bob', 'Male', 88)
     t = Teacher('Alice', 'Female', 'English')
     
     isinstance(s, Student)
     True
     
     isinstance(p , Person)
     True
     
     isinstance(t , Student)
     False
    复制代码
  • 特殊方法

    1  str和repr
      class Person(object):
         def __init__(self, name, gender):
             self.name = name
             self.gender = gender
         def __str__(self):
             return '(Person: %s, %s)' % (self.name, self.gender)
    
     p = Person('Bob', 'male')
     print(p)
     (Person: Bob, male)
     
     2 Python的 sorted() 按照默认的比较函数 cmp 排序
     
     class Student(object):
         def __init__(self, name, score):
             self.name = name
             self.score = score
         def __str__(self):
             return '(%s: %s)' % (self.name, self.score)
         __repr__ = __str__
     
         def __cmp__(self, s):
             if self.name < s.name:
                 return -1
             elif self.name > s.name:
                 return 1
             else:
                 return 0
     
     L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77)]
     print(L)
     [(Tim: 99), (Bob: 88), (Alice: 77)]
     
     3 len
     class Students(object):
         def __init__(self, *args):
             self.names = args
         def __len__(self):
             return len(self.names)
             
     ss = Students('Bob', 'Alice', 'Tim')
     print (len(ss))
     3
    复制代码
  • 在Python中,函数其实是一个对象

    class Person(object):
          def __init__(self, name, gender):
              self.name = name
              self.gender = gender
      
          def __call__(self, friend):
              print ('My name is %s...' % self.name)
              print ('My friend is %s...' % friend)
      
      p = Person('Bob', 'male')
      p('Tim')
      
      My name is Bob...
      My friend is Tim...
    复制代码

2 总结

通过Python技术栈与Spark大数据数据平台整合,必然需要本文进行详细对比,粗陋成文,在于作者复习,勿怪。

秦凯新 于深圳 201812132319

版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Apache源代码全景分析第1卷

Apache源代码全景分析第1卷

2009-5 / 88.00元

《Apache源代码全景分析第1卷:体系结构与核心模块》是“Apache源代码全景分析”的第1卷。书中详细介绍了Apache的基础体系结构和核心模块的实现机制,包括配置文件、模块化结构、多任务并发,以及网络连接和请求读取,其中多任务并发体系结构是《Apache源代码全景分析第1卷:体系结构与核心模块》分析的重点,讨论了Prefork、Worker及WinNT三种MPM。《Apache源代码全景分析......一起来看看 《Apache源代码全景分析第1卷》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具