上次我们说到,关于python面向对象
面向对象是什么
面向对象和面向过程的区别
类和对象
python中如何定义类和实例化对象
类的属性和方法
这里我们讲面向对象的特征:封装,继承,多态,三大特征。
也有说抽象加在一起算作是四大特征,这一观点并未得到公认。
封装
什么是封装?
广义的封装:将事物的细节进行封起,提供好用的方法供使用者使用。
面向对象的封装:
1.将类的属性和方法封装成一个或者多个类,使用的时候调用对象的属性和方法。
2.将类的属性进行封装(私有化private),仅供类内部进行访问,提供公开的方法(getter和setter)进行访问。
python中如何实现封装
对于上面的第二点,才是面向对象封装特性的重点。
请看下面这段代码:
# -*- coding: utf-8 -*-
class Richman:
def __init__(self):
self.money = 1000000
self.company = "alibaba"
def speak(self):
print("我对钱没有兴趣!")
print("一个月一块钱的工资!")
if __name__ == "__main__":
rich1 = Richman()
print(rich1.money)
rich1.money = 1000
print(rich1.moneyA)
运行结果如下,可以看到可以直接访问对象的属性和修改属性,这样是极为不好的,不符合封装的特性。
如何修改呢,将属性进行私有化。
class Richman:
def __init__(self):
self.__money = 1000000
self.__company = "alibaba"#__属性即是私有属性。
def speak(self):
print("我对钱没有兴趣!")
print("一个月一块钱的工资!")
if __name__ == "__main__":
rich1 = Richman()
print(rich1.money)
rich1.money = 1000
print(rich1.moneyA)
修改为私有属性,则无法进行访问,如要进行访问则需要对外界提供公开的方法。
同理,属性可以私有,方法同样可以私有。
三种封装访问方式
上面说到封装特性的时候,采用getter,和setter进行提供公开的访问
1.getter和setter
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.get_name())
print(p1.get_age())
print(p1)
p1.set_name("wangwang")
p1.set_age("20")
print(p1)
提供了getter和setter可以对私有属性进行访问和修改。
2.将访问方法再进行封装,让用户感觉没有变化。
使用property方法
如下的:将之间的方法再提供给用户。用户使用起来没有变化,get在前,set在后
name = property(get_name,set_name)
age = property(get_age,set_age)
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
name = property(get_name,set_name)
age = property(get_age,set_age)
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.name)
print(p1.age)
print(p1)
p1.name = "wangwang"
p1.age = "20"
print(p1)
可以看到用户访问起来并没有觉得有任何不同。
3.使用property装饰器
可以说是property(get,set)的变式写法
将property()写为如下形式:
@property #装饰器
def gender(self):
return self.__gender
@gender.setter #一般使用私有属性的名称作为@的值
def gender(self,gender):
self.__gender = gender
代码如下:
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
#property(get,set)的变式写法
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self,gender):
self.__gender = gender
name = property(get_name,set_name)
age = property(get_age,set_age)
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.name)
print(p1.age)
print(p1)
p1.name = "wangwang"
p1.age = "20"
print(p1)
print(p1.gender)
p1.gender = "女"
print(p1.gender)
print(p1)
故在定义类之时,一定要进行对类进行封装,私有化其属性,再提供公开的get和set进行访问。具有一定安全性。
继承
继承是什么?下一代获得上一代遗留的东西的过程称为继承。
在python之中,一个类如何继承另一个类呢,我通过代码进行演示。
class Richman:
def __init__(self):
self.money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我对钱没有兴趣!")
print("一个月一块钱的工资!")
class Son(Richman):
pass
if __name__ == "__main__":
s1 = Son()
print(s1.money)
s1.money = 1000
print(s1.money)
s1.speak()
可以看到,son类中什么内容也没有写,是继承了richman中的属性和方法。
下面我将money属性改为私有,可以看到报错。
self.__money = 1000000
是因为继承只能继承公开的属性和方法,私有属性和方法无法继承
重写override
如果对继承的方法不满意怎么办,不合适,那么就需要对方法进行重写。
class Richman:
def __init__(self):
self.__money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我对钱没有兴趣!")
print("一个月一块钱的工资!")
def working(self):
print("A你是个好同志,做事我放心!")
print("B你是个lowB,干事不好!")
class Son(Richman):
def working(self):
print("还是自己人来好一点!,我把自己兄弟叫来")
if __name__ == "__main__":
s1 = Son()
r1 = Richman()
s1.speak()
r1.speak()
s1.working()
r1.working()
对父类的working方法进行了重写,可以看到重写后则就是调用的是重写后在该类中的working,父类和子类中的方法,调用时是就近原则。
一道常见的面试题:
Python中有函数重载和方法重写吗?
答案:没有函数重载,有方法重写。
why:
overload:名称相同,参数不同或者类型不同的一些函数。
1.由于python是弱数据类型语言,则类型不会不相同,
2.由于py是解释型语言,执行时候后者所谓重载的函数会覆盖之前的函数,则没有重载。
重写就不用说了,上面演示的就是重写
继承的作用和目的是为了:代码复用和多态。代码复用是继承的本质。
super关键字和多继承
同样是面向对象,java不支持多继承。
py如何支持多继承的呢?
如 class Son(Richman,xxx,xxxx,…)一个类可以有多个父类。
这有一个问题:同时继承多个类,类中都用同一个方法,该如何调用呢?
在py3中现在使用的是新式类,采用广度优先,即继承的顺序来调用。
在旧式类中,采用的是深度优先,按照继承的类的深度来调用,如果深度想同,则再按照继承顺序。
super ,超级的意思,----》算是个指针,指向父类。
在子类中使用。
super().方法名()
使用如下:
# -*- coding: utf-8 -*-
class Richman:
def __init__(self):
self.__money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我对钱没有兴趣!")
print("一个月一块钱的工资!")
def working(self):
print("A你是个好同志,做事我放心!")
print("B你是个lowB,干事不好!")
class Son(Richman):
def working(self):
print("还是自己人来好一点!,我把自己兄弟叫来")
def test(self):
super().working()
if __name__ == "__main__":
s1 = Son()
r1 = Richman()
s1.speak()
r1.speak()
s1.working()
r1.working()
s1.test()
结果:
在初始化函数的时候,是对子类操作,不像其他语言。如下:
class RichMan:
def __init__(self):
print("这是父类!")
class Son(RichMan):
def __init__(self):
print("这是子类!")
if __name__ == "__main__":
s1 = Son()
代码执行:
如果需要调用父类,则需要使用super。
class RichMan:
def __init__(self):
print("这是父类!")
class Son(RichMan):
def __init__(self):
super().__init__()
print("这是子类!")
if __name__ == "__main__":
s1 = Son()
super()调用的方法中是有参则传参。
多态
何为多态?
对象的多种状态。
在继承的基础上,父类引用指向子类实例的现象,称为多态。
比如java中父类list,一个子类arraylist。
List ls = new ArrayList()
父类调用子类方法,而py是弱数据类型,上面例子成为:
ls = ArrayList()
由于py是弱数据类型,天生就是支持多态的,则其不关心多态的问题。
这里就不多讲了。
今天的分享就到这里了,喜欢的小伙伴可以点赞和关注呀!博主持续分享。