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

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

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


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

查看所有标签

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

Web Applications (Hacking Exposed)

Web Applications (Hacking Exposed)

Joel Scambray、Mike Shema / McGraw-Hill Osborne Media / 2002-06-19 / USD 49.99

Get in-depth coverage of Web application platforms and their vulnerabilities, presented the same popular format as the international bestseller, Hacking Exposed. Covering hacking scenarios across diff......一起来看看 《Web Applications (Hacking Exposed)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器