整章对比java的类与对象学习,注意异同点
Python与面向对象
- 所谓面向对象编程,就是编程过程中干活的都是“对象”。举个不太恰当的例子。好比我们大学生。类-相当于学校的规范化培养,规定了我们每一个人的学号,制定了相同的专业课程等。学校的这些规范和课程不能直接地产生价值。但是学校培养出来的学生可以啊,学生就是“对象”。用来产生价值的是“对象”,不是“类”。类里面规定了一些属性,方法。以“类”为模板创造(实例化)出来的“对象”是具体使用这些方法来产生效果的实施者。
类
- 跟java对象一样,就是个模板,用来创建实例(也就是对象)。
类里面有哪些概念呢?
1,类变量;2,数据成员;3,方法重写;4,实例变量;5,继承;6,多态;7,方法;8,对象;9,构造方法
接下来对比java这些概念学习
- Python创建一个类
class EmptyClass:
pass
构造方法
- java构造方法是与类名同名的,new一个对象的时候自动执行(同名不同参数叫重载);Python的构造方法是 _init_(self, 参数…),该函数在实例化一个对象的时候自动执行,该方法里面的对象也叫实例变量,就是不同对象不共享。外面的叫成员变量,所有对象共享;
- 这个self相当于C语言的指针this,指的是实例本身,当成一个隐藏的参数就行了,传参的时候忽略不计,不管这个self;
这个self有点东西啊!
self其中一个作用:当子类同名方法覆盖了父类同名方法的时候,如果还想调用父类的方法,“ 父类名.父类方法(子类实例)”------这个时候传到父类方法的子类实例就是self;不懂没关系,继续学,后面会反复的提到子类使用父类覆盖方法的;
class Ball:
def __init__(self, name):
self.name = name #必须使用 self. 指的是本实例;
def kick(self):
print("我叫%s,该死的,谁踢我..." % self.name)
a = Ball("球A")
b = Ball("球B")
c = Ball("球C")
a.kick()
# 我叫球A,该死的,谁踢我...
b.kick()
# 我叫球B,该死的,谁踢我...
Python继承父类的时候会继承父类公有的所有方法和变量,但是会被同名的方法和变量覆盖(构造方法也一样会被覆盖),如果想继承父类的构造方法,必须如下:
方式1:
super(当前类名称,self).你要调的父类的属性或方法
方式2:
super().你要调的父类的属性或方法 //同java的调用方式
方式3:
类名称.你要调的父类的属性或方法(self)
类中的属性
- 刚刚上面说了,构造方法中可以初始化一些属性,形如:dog = Dog(“旺财”)。这个“旺财”就是被构造函数中的第二个参数接收了(第一个是self),如果Dog(“旺财”,“小强”),“小强”会被构造函数的第三个参数接受,后面以此类推。
class Dog:
def __init__(self,a,b):
self.name1=a
self.name2=b
dog=Dog("旺财","小强")
print("我叫%s,%s是我家的狗 "%(dog.name1,dog.name2))
#我叫旺财,小强是我家的狗
- 成员属性(构造函数中的属性)必须使用“self”加点的形式定义,形如:self.name。不能直接在构造函数中直接定义变量名,不带self的变量名在函数执行完变量就会被销毁。不信你看:
class Dog:
def __init__(self,a,b):
self.name1=a
age=b
dog=Dog("小强",12)
print("我叫%s "%dog.name1) #我叫小强
print("我今年%d岁 "%dog.age)
#AttributeError: 'Dog' object has no attribute 'age'
没有这个属性age,明明我在构造函数中加了age?仅仅是因为没有self给它绑定到创建的对象中,这句话看的明白的看,看不明白的也没关系,不影响使用,只用知道,构造函数中的属性要用self来点一下。
类中的方法
- 方法就是函数,不同位置的不同叫法罢了。唯一的区别就是,再类里面定义方法必须第一个参数的位置是self(不一定非要命名为self,这个名字你随便,但是,这个参数所代表的是一个实例对象),其他参数随意,你看:
class Dog:
def __init__(abc,a,b):
abc.name1=a
abc.name2=b
def run(self, age):
print("我叫%s,今年%d岁,我跑的比%s快 "%(self.name1,age,self.name2))
def play(lol):
print("我叫%s,%s是我家的狗 "%(lol.name1,lol.name2))
dog=Dog("阿福","旺财")
dog.run(12)
dog.play()
#我叫阿福,今年12岁,我跑的比旺财快
#我叫阿福,旺财是我家的狗
留意我定义类里面方法的参数,不一定是self哦。使用的时候传参数也是跳过第一个参数,跟实例化一个对象一样。传入的参数第一个就是self后的面的第一个参数;self句当成一个占位符行了(self在调用父类方法的时候,爸子类实例当成参数传入的时候会被self接收,不理解的接着往下看);
- 方法补充:跟java不同的是,Python中的方法是有方法对象的;比如上面的play() 方法。我们使用这个方法的方式是直接dog.play()来执行的;但是,"dog.play"不带括号是什么鬼?Python中,方法不带括号就叫方法对象,可以用个变量把方法对象存起来,等什么时候想执行了,再在这个变量后加上括号就能直接执行了,举个例子:
class Dog:
def __init__(abc,a,b):
abc.name1=a
abc.name2=b
def run(self, age):
print("我叫%s,今年%d岁,我跑的比%s快 "%(self.name1,age,self.name2))
def playplayplayplay(lol):
print("我叫%s,%s是我家的狗 "%(lol.name1,lol.name2))
dog=Dog("阿福","旺财")
newName=dog.playplayplayp
print("这个方法名字太长了,而且,我现在也不想执行这个方法,先用个变量存起来吧!")
print("方法对象是个什么类型呢?是个 %s。"%type(newName))
newName()
# 这个方法太长了,懒得敲,而且,我现在也不行执行这个方法,先用个变量存起来吧!
# 方法对象是个什么类型呢?是个 <class 'method'>。
# 我叫阿福,旺财是我家的狗
私有属性
- 什么叫私有,就是只能我自己用,比人不能用。私有属性呢,形如__name,属性前两下划线,他的对象不能直接通过dog.age来访问,不信你看:
class Dog:
def __init__(self,a,b):
self.__name=a
self.age=b
dog=Dog("旺财",12)
print(dog.age)
print(dog.__name)
# AttributeError: 'Dog' object has no attribute '__name'
# 12
- 那应该怎么访问呢?既然是私有的,那么说明外面不能直接拿到到类里面定义的私有变量,它管不了类里面自己人访问啊,私有是对外人私有,对自己人还是开放的。跟java的处理思路一样,在类里面加上访问和修改get和set方法就好了,不信你看:
class Dog:
def __init__(self,a):
self.__name=a
def geTheName(self):
return self.__name
def setTheName(self,b):
self.__name=b
dog=Dog("旺财")
print("大家好,我是%s"%dog.geTheName())
dog.setTheName("小强")
print("大家好,我现在是%s"%dog.geTheName())
#大家好,我是旺财
#大家好,我现在是小强
私有方法
- 属性都能私有了,方法当然也能私有啊!在方法名前加上两下划线,形如 __play(self)。上面也说了私有属性不能直接被实例使用,但是可以被类里面的方法访问。私有方法也是一样的,自己不能被实例使用,但是可以被自己内部的其他方法使用啊!不信你看:
class Dog:
def __init__(abc,a,b):
abc.name1=a
abc.name2=b
def __run(self):
print("我叫%s,我跑的比%s快 "%(self.name1,self.name2))
def play(self):
print("我是play,我要调用__run方法啦!")
self.__run()
dog=Dog("阿福","旺财")
dog.play()
dog.__run()
# 我是play,我要调用__run方法啦!
# 我叫阿福,我跑的比旺财快
# AttributeError: 'Dog' object has no attribute '__run'
小Tips:这个时候有人会想,私有方法实例不能访问,你写成私有的干啥?还不如直接把代码复制到一个公用方法里面得了,整的花里胡哨的还不好理解。这个涉及到模块安全机制了。比如银行转账业务中,我要完成转账10块钱的业务逻辑,银行转账涉及到很多层的安全验证,所以我把转10块钱的逻辑封装在一个转账的方法中。如果该方法公有的话,任何人都能直接调用包含安全验证的模块,通过反射机制有可能直接够拿到安全验证的代码,多危险。这个例子不怎么恰当,感性地了解一下就好了
继承
- 先说说继承:在古代,子承父业,儿子能够继承到父亲的房子,票子…儿子都能够直接使用,但是,父亲的小妾儿子就不能继承啦,小妾是父类的私有财产,只要儿子继承了父类的财产,儿子不就可以吃现成的了吗。在Python中,为了提高代码的利用率,也是为了丰富类的功能,引入继承机制。但不是无脑什么都继承的啊。
- 跟java不同的地方是Python可以实现多继承,实现方式:(类参数。。)
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
#或者
class DerivedClassName(modname.BaseClassName):
<statement-1>
.
.
.
<statement-N>
- 一个类里面目前只有属性和方法这两种东西,儿子出了继承父类以外,儿子也能自己定义自己的属性和方法啊!但是,一档你定义的方法和属性的名字跟从父类继承过来的方法和属性名字重合了,这个时候,儿子定义的同名属性和同名方法会覆盖掉父类的属性方法。
# 父类
class people:
name = ''
age = 0
__weight = 0 # 定义私有属性,私有属性在类外部无法直接进行访问
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("我是父类:%s 说: 我 %d 岁。" % (self.name, self.age))
# 子类(继承people)
class student(people):
grade = '' #
def __init__(self, n, a, w, g):
# 调用父类的构函,或者supper().__init__(self, n, a, w)
people.__init__(self, n, a, w)
self.grade = g
# 重写父类的方法
def speak(self):
print("我是子类:%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
s = student('小马的程序人生', 10, 60, 3)
s.speak()
super(student,s).speak(). #方法一 ,外部调用父类被重写的原方法
people.speak(s) #方法二 ,外部调用父类被重写的原方法
# 我是子类:小马的程序人生 说: 我 10 岁了,我在读 3 年级
# 我是父类:小马的程序人生 说: 我 10 岁。
# 我是父类:小马的程序人生 说: 我 10 岁。
- 在子类里面想调用被覆盖的父类方法:1,super(student, self).speak()
2, people.speak(self) - 外面实例想调用被覆盖的父类方法:1,super(student,s).speak()。2,people.speak(s)
想想类里面调用覆盖的父类方法和外面实例调用父类覆盖的方法有啥区别?就是一个self,和一个实例s的区别,看到没。本质上是一个东西,实例s,是用self来接收的
# 父类
class people:
name = ''
age = 0
__weight = 0 # 定义私有属性,私有属性在类外部无法直接进行访问
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("我是父类:%s 说: 我 %d 岁。" % (self.name, self.age))
# 子类
class student(people):
grade = ''
def __init__(self, n, a, w, g):
# 调用父类的构函,或者supper().__init__(self, n, a, w)
people.__init__(self, n, a, w)
self.grade = g
# 重写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
def play(self):
# 用来验证 父类子类调用父类被覆盖方法
super(student, self).speak()
people.speak(self)
s = student('旺财', 10, 60, 3)
s.play()
super(student,s).speak()
people.speak(s)
#--子类调用
#我是父类:旺财 说: 我 10 岁。
#我是父类:旺财 说: 我 10 岁。
#--实例调用
#我是父类:旺财 说: 我 10 岁。
#我是父类:旺财 说: 我 10 岁。
- 若想在子类中使用夫类的构造方法,在子类的_ini_(self):
方式一:父类名.__init__(self)
方式二:super().__init__()
- 多继承:Python 虽然支持多继承的形式,但我们一般不使用多继承,因为容易引起混乱
注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,Python 从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法
# 类定义
class People:
# 定义基本属性
name = ''
age = 0
# 定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
# 定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" % (self.name, self.age))
# 父类1(但是这个父类继承了people
)
class Student(People):
grade = ''
def __init__(self, n, a, w, g):
# 调用父类的构函
People.__init__(self, n, a, w)
self.grade = g
# 覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
# 父类2
class Speaker:
topic = ''
name = ''
def __init__(self, n, t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s" % (self.name, self.topic))
# 多重继承
class Sample01(Speaker, Student):
a = ''
def __init__(self, n, a, w, g, t):
Student.__init__(self, n, a, w, g)
Speaker.__init__(self, n, t)
# 方法名同,默认调用的是在括号中排前地父类的方法
test = Sample01("Tim", 25, 80, 4, "Python")
test.speak()
# 我叫 Tim,我是一个演说家,我演讲的主题是 Python
class Sample02(Student, Speaker):
a = ''
def __init__(self, n, a, w, g, t):
Student.__init__(self, n, a, w, g)
Speaker.__init__(self, n, t)
# 方法名同,默认调用的是在括号中排前地父类的方法
test = Sample02("Tim", 25, 80, 4, "Python")
test.speak()
# Tim 说: 我 25 岁了,我在读 4 年级
多态
- 多态是在继承的基础上发展出来的概念;多态本质就是重写父类的方法;什么意思呢?举个例子如下:同一个run方法,cat和dag继承不做任何改变,表现都是一样的,就是父类的表现;但是,同一个Animal的父类的speak方法,cat和dog分别继承,然后各自改写了各自继承的方法,从而统一个方法表现不同。这就叫做多态。
class Animal:
class Animal:
def run(self):
print("动物跑")
def speak(self):
print("我是父类方法:我是一个Animal")
class Cat(Animal):
def speak(self):
print("我是子类Cat,我是一只猫")
class Dog(Animal):
def speak(self):
print("我是子类Dog,我是一条狗")
cat=Cat()
cat.speak()
cat.run()
dog=Dog()
dog.speak()
dog.run()
#我是子类Cat,我是一只猫
#动物跑
#我是子类Dog,我是一条狗
#动物跑
类与对象的组合使用
- 组合使用没啥好说的,看例子就能弄懂。Turtle(x)和Fish(y)是两个对象。self.turtle,self.fish所接受的是两个对象,操作的时候要当成对象来操作,用点的方式拿属性和方法;
class Turtle:
def __init__(self, x):
self.num = x
class Fish:
def __init__(self, x):
self.num = x
class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))
p = Pool(2, 3)
p.print_num()
# 水池里面有乌龟2只,小鱼3条
其他
- 剩下都是类拓展的知识了。学习面向对象,重点是弄懂,类,对象,继承是什么,之间的属性或者方法是怎么调用的就行了。