一、封装(隐藏):
隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将"细节封装起来",只对外暴露“相关调用方法”。通过私有属性、私有方法的方式实现封装。
Python追求简洁的语法,没有严格的语法级别的"访问控制符",更多的是依靠程序员的自觉实现。
二、继承:
如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作难度,已有的类,我们称为"父类或基类",新的类,我们称为“子类或派生类”。
继承可以让子类具有父类的特性,提高了代码的重用性。
Python支持多重继承,一个子类可以继承多个父类,继承的语法格式如下:
class 子类类名(父类1,父类2,…):
类体
如果在类定义中没有指定父类,则默认父类是object类,也就是说object类是所有类的父类,因此所有类都有object类的属性和方法,
object类里面定义了一些所有类共有的默认实现,比如__init()__,__new__()。
定义子类时,必须在其构造函数中调用父类的构造函数(此处只是逻辑上的必须,语法上没有严格要求,但是一般要调),调用格式如下:
父类名.__init__(self,参数列表)
#测试继承的基本使用
class Person:
def __init__(self,name,age): #属性在构造器中
self.name=name
self.__age=age #私有属性(子类可以调用,但是不能用,也就是说子类继承了父类所有的属性方法,但是父类私有的属性方法子类不能用)
def say_age(self):
print("嘿嘿,不告诉你")
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age)#必须显式的调用父类初始化方法,不然解释器不会去调用
self.score=score
# Student——>Person——>object类
print(Student.mro())#查看类的继承层次结构
s=Student("张无忌","18","100")
s.say_age()
print(s.name)
# print(s.age) 父类的私有属性,子类不能用
print(dir(s))
print(s._Person__age)#实例对象._类名__私有属性 这样才可以用(这说明Python中并没有完全意义上的私有,需靠程序员的自觉性去维护)
如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者重写父类的构造方法。
如果子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__
如果重写了__init__ 时,实例化子类,就不会调用父类已经定义的 __init__
如果重写了__init__ 时,要继承父类的构造方法,可以使用 super 关键字
类成员的继承和重写:
1.成员继承:子类继承了父类除构造方法之外的所有成员。
2.方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类中的方法,也称为重写。
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age
def say_age(self):
print("我的年龄是",self.__age)
def say_introduce(self):
print("我的名字是{}".format(self.name))
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age)
self.score=score
def say_introduce(self):
'''重写了父类的方法'''
print("报告老师,我的名字是{}".format(self.name))
s=Student("张无忌",18,100)
s.say_age()
s.say_introduce()
#打印结果
我的年龄是 18
报告老师,我的名字是张无忌
通过类的方法mro()或者类的属性_mro_可以输出这个类的继承层次结构。
通过类的方法dir()查看对象属性
class A:
pass
class B(A):
pass
class C(B):
pass
#mro()查看类的继承层次结构
print(C.mro()) #或者用 print(C.__mro__)
#dir()查看对象属性
a=A()
print(dir(a))
#结果如下:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
重写__str__方法:
用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮助我们查看对象的信息。_str_()可以重写。
class Person():
def __init__(self,name):
self.name=name
p=Person("张三丰")
print(p)
#打印结果如下: object类中__str__()的默认实现,打印类的信息
<__main__.Person object at 0x03110D30>
__str__()重写后
class Person():
def __init__(self,name):
self.name=name
def __str__(self):
return "名字是:{}".format(self.name)
p=Person("张三丰")
print(p)
#打印结果如下:
名字是:张三丰
关于多重继承:
Python支持多重继承,一个子类可以有多个“直接父类”,这样就具备了多个父类的特点,但是由于这样会把“类的整体层次”搞得很复杂,尽量避免使用。
#测试多重继承
class A:
def aa(self):
print("aa")
class B:
def bb(self):
print("bb")
class C(A,B):
def cc(self):
print("cc")
c=C()
#调用方法
c.aa()
c.bb()
c.cc()
#打印结果:
aa
bb
cc
mro()
Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索。
MRO(Method Resolution Order):方法解析顺序,我们可以通过mro()方法获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找到。
class A:
def aa(self):
print("aa")
def say(self):
print("say AAA!")
class B:
def bb(self):
print("bb")
def say(self):
print("say BBB!")
class C(A,B):
def cc(self):
print("cc")
c=C()
print(C.mro())
c.say() #解释器寻找方法是"从左到右的顺序"寻找,此时会执行A类中的say()
#打印结果
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
say AAA!
super()获得父类定义
在子类中,如果想要获得父类的方法时,我们可以通过super()来做,super()代表父类的定义,而不是父类对象。
#测试super()代表和父类有关,而不是父类对象!
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
# A.say(self) 也可调用
super().say() #()中没有传self说明调用的是类方法,()中传self说明调用的是类的实例化方法
print("B:",self)
B().say()
三、多态:
多态(polymorphism)是指同一个方法调用,由于对象不同可能会产生不同的行为。
注意:
1.多态是方法的多态,属性没有多态
2.多态的存在有两个必要条件:继承、方法重写
(一个类它继承了一个类,但是它又改写了它父类的方法,这样在调用这个方法时,就会因为实例对象的不同而调用的方法不同,也就是说看这个实例对象实例化时是用父类实例化的,还是子类实例化的,是父类实例化的,结果就是父类的方法,是子类实例化的,结果就是子类的方法)
class Man:
def eat(self):
print("饿了,吃饭了!")
class Chinese(Man):
def eat(self):
print("中国人用筷子吃饭")
class English(Man):
def eat(self):
print("英国人用刀叉吃饭")
class Indian(Man):
def eat(self):
print("印度人用右手吃饭")
def manEat(m):
if isinstance(m,Man):
m.eat()
else:
print("不能吃饭")
#子类Chinese实例化的
manEat(Chinese())
#子类English实例化的
manEat(English())
#Person这个实例化对象,父类实例化的
Person=Man()
manEat(Person)
#运行结果
中国人用筷子吃饭
英国人用刀叉吃饭
饿了,吃饭了!