内容简介:版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。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,如有任何学术交流,可随时联系。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python数据处理(二):处理 Excel 数据
- R|数据处理|因子型数据
- 大数据 -- 下一代数据处理技术
- Python数据抓取(1) —数据处理前的准备
- 大数据生态圈之流式数据处理框架选择
- 流式数据处理在百度数据工厂的应用与实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。