python面向对象2-类的继承
实践出真知,去自己实践代码吧
类的继承基本语法:
class 派生类名(基类名):
...
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
第一部分
如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法。
**
举例1
**(不重写父类的构造方法):
```python
class Father(object):
def __init__(self, name):
self.name = name
print("name: %s" % (self.name))
def getName(self):
return 'Father ' + self.name
class Son(Father): # 子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__。
def getName(self):
return 'Son ' + self.name
if __name__ == '__main__':
son = Son('runoob')
print(son.getName())
结果: name: runoob
Son runoob
**
举例2
**(重写父类的构造方法):
class Father(object):
def __init__(self, name):
self.name = name
print("name: %s" % (self.name))
def getName(self):
return 'Father ' + self.name
class Son(Father):
def __init__(self, name):
print("hi")
self.name = name
def getName(self):
return 'Son ' + self.name
if __name__ == '__main__':
son = Son('runoob')
print(son.getName())
结果:hi
Son runoob
**
举例3
**(重写父类的构造方法):
如果重写了__init__ 时,要继承父类的构造方法,可以使用 super 关键字:
语法: super(子类,self).__init__(参数1,参数2,....)
或者 super().__init__(参数1,参数2,....)
class Father(object):
def __init__(self, name):
self.name = name
print("name: %s" % (self.name))
def getName(self):
return 'Father ' + self.name
class Son(Father):
def __init__(self, name):
super(Son, self).__init__(name)
print("hi")
self.name = name
def getName(self):
return 'Son ' + self.name
if __name__ == '__main__':
son = Son('runoob')
print(son.getName())
结果: name: runoob
hi
Son runoob
第二部分(这部分是一些基本概念,实践操作理解看第三部分)
(1)在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
(2)Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
(3)在类的继承中,私有属性,类变量并没有什么特殊,都可以在子类中使用,但私有方法不能直接调用,可以被重写。
(4)查看继承的特殊属性和方法
__base__ : 类的基类
__based__ : 类的基类元组
__mro__ : 显示方法查找顺序,基类的元组
__subclasses__() : 类的子类列表
(5)继承中的访问控制
-
私有的都是不可以访问的,但是本质上依然是改了名称放在这个属性所在类的__dict__中
-
继承时,公有的,子类和实例都可以随意访问,私有成员被隐藏了,子类和实例不可直接访问
-
当私有变量所在的类内的方法中可以访问这个私有变量
第三部分(针对单继承)
子类中调用父类的方法:
1:类名.方法名(self,参数)
2:super(子类名,self).方法名(参数)
3:super().方法名(参数)
注:在下面的代码中我发现可以直接在子类中通过self.方法名(参数)调用父类中没有被重写的的方法,若是方法已经被子类重写,则调用的是被重写后的方法。
创建Animals(动物)基类:
class Animals(object):
eye='褐色' # 类变量
def __init__(self,name,color,age):
self.name=name
self.color=color
self.set_age(age) # 定义私有属性
print("调用父类的构造方法")
def set_age(self,age):
self.__age=age
def get_age(self):
return self.__age
def channel(self):
print("调用父类的公共方法channel()")
def choice(self):
print("调用父类的公共方法choice()")
def sd(self):
print("sssssssss")
def __performance(self):
print("调用父类的私有方法")
pass
创建Cat(猫)子类:
class Cat(Animals):
def __init__(self,name,color,age,food):
super().__init__(name,color,age)
self.food=food
# def channel(self):
# super().channel()
def choice(self):
print("重写父类的公共方法choice()")
Animals.sd(self) # 类名.方法名(self,参数)
self.channel() # self.被重写后的父类的方法名(参数)
def channel(self):
print("重写父类的公共方法channel()")
print(f"{self.name}的年龄是:{self.get_age()},食物是{self.food}")
def __performance(self):
print("在类的继承中,私有属性,类变量并没有什么特殊,都可以在子类中使用,但私有方法不能直接调用,可以被重写")
Animals.eye='水晶色'
print(f"{self.name}的眼睛是{Animals.eye}的")
def jiekou(self): # (创建接口方法间接使用私有方法)
self.__performance()
pass
cat=Cat('波斯猫','白色',5,'雪山旗鱼')
print(dir(cat))
cat.choice()
cat.channel()
cat.jiekou()
print(cat.get_age())
第四部分 (针对多级继承,代码继承上面的类)
创建Dog(狗)子类:(注意:狗类继承的是猫类)
class Dog(Cat):
def pao(self):
print(f"{self.name}追着波斯猫跑")
def k(self):
# self.jiekou()
super(Dog,self).jiekou()
pass
dog=Dog('旺财','黄色',4,'大骨头')
print(dog.__dict__)
print(dir(dog))
dog.k()
print(Dog.__mro__) # 该方法可以列出类的继承顺序链
第四部分 (针对多继承,感觉和上面的多级继承差不多)
*************(以下代码与上面代码无关)
创建 Animal类(基类)
class Animal(object):
def __init__(self,name,age):
self.name=name
self.age=age
def Perform(self):
print("动物世界真好看")
pass
创建 Bird类(基类)
class Bird(object):
def __init__(self,name,age,food):
self.name=name
self.age=age
self.food=food
def Perform(self):
print("鸟类能飞")
pass
创建Eagle类(子类,同时继承上面的两个类)
class Eagle(Bird,Animal):
pass
eagle=Eagle('老鹰',10) # 系统报错:TypeError: __init__() missing 1 required positional argument: 'food'
eagle=Eagle('老鹰',10,'肉') # 系统不报错 说明Eagle类默认继承了Bird类的构造方法,参数要与Bird类的参数保持一致
print(eagle.__dict__) # {'name': '老鹰', 'age': 10, 'food': '肉'}
class Eagle(Animal,Bird):
pass
eagle=Eagle('老鹰',10) # 系统不报错,说明说明Eagle类默认继承了Animal类的构造方法,参数要与Animal类的参数保持一致
print(eagle.__dict__) # {'name': '老鹰', 'age': 10}
由此我们可以得出:多继承下的子类按照继承的顺序依次查找所需要的属性或方法。
通过下面的代码再加深理解:(继承的类先后顺序不同)
——class Eagle(Animal,Bird)
class Eagle(Animal,Bird):
pass
#
eagle=Eagle('老鹰',10)
eagle.Perform()
print(Eagle.__mro__) # 列出继承顺序链,依次查找
# (<class '__main__.Eagle'>, <class '__main__.Animal'>, <class '__main__.Bird'>, <class 'object'>)
——class Eagle(Bird,Animal)
class Eagle(Bird,Animal):
pass
eagle=Eagle('老鹰',10,'肉')
eagle.Perform()
print(Eagle.__mro__)
#(<class '__main__.Eagle'>, <class '__main__.Bird'>, <class '__main__.Animal'>, <class 'object'>)