Python基础(八)
Python基础(八)
1、继承
1.1、简介
- 继承是一种创建类的方式,新建的类可称为子类或派生类,父类可称为基类或超类
- 继承可以使得子类具有父类中公共的属性或者方法
- 继承具有传递性,即子类拥有父类以及父类的父类中封装的所有属性和方法。
- python支持多继承,一个类可以支持一个或多个父类
- 在python3中如果没有继承任何类,默认继承object类
1.2、继承
- 优点
- 解决了类与类之间代码冗余的问题
- 子类可以同时遗传多个父类的属性,最大限度的重用代码
- 可以重点关心子类独有的方法
- 缺点
- 多继承违反人的思维习惯,代码的可读性会变差,不建议使用多继承。
1.3、单继承
1. 介绍
子类只继承一个父类
2. 语法
class 类名(父类名):
pass
3. 单继承的查找顺序
对象>子类>父类>父父类,找到方法或属性后不会继续向下查找。
4. 例子
class Animal:
def eat(self):
print("吃")
def run(self):
print("跑")
class dog(Animal):
def dog(self):
print("dog")
class cat(Animal):
def cat(self):
print("cat")
class ragdoll(cat):
def embrace(self):
print("ragdoll")
c1 = cat()
c1.eat() # 吃
c1.cat() # cat
r1 = ragdoll()
r1.eat() # 吃
r1.cat() # cat
r1.embrace() # ragdoll
# 查看调用顺序 类名.mro()
print(ragdoll.mro()) # [<class '__main__.ragdoll'>, <class '__main__.cat'>, <class '__main__.Animal'>, <class 'object'>]
1.4、多继承
1. 介绍
多继承,即子类有多个父类,并且具有它们的特征
2. 语法
class 类名(父类A名,父类B名):
pass
3. 查找顺序
在python3中按照广度有限进行查找,找到方法或属性后不会继续向下查找。
class G:
pass
class E:
pass
class F(G):
pass
class B(E):
pass
class C(F):
pass
class D(G):
def test(self):
print('from D')
class A(B, C, D):
pass
print(A.mro()) #[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.G'>, <class '__main__.D'>, <class 'object'>]
# -A-B-E-C-F-D-G
4. 例子
class A():
def out_text(self):
print('from A')
class B(A):
def out_text(self):
print('from B')
class C(A):
def out_text(self):
print('from C')
class D(B,C):
pass
obj = D()
obj.out_text() # 结果---->from B
''' 可以打印出mro列表查看顺序'''
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
1.5、重写方法
1. 介绍
重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法。
2. 例子
class Animal:
def eat(self):
print("吃")
def run(self):
print("跑")
def bark(self):
print("芜湖")
class cat(Animal):
def cat(self):
print("cat")
def bark(self):
print("喵喵")
c = cat()
c.run() # 跑
c.bark() # 喵喵
1.6、调用父类
1. 介绍
子类可以通过类名或者是super()调用父类的属性
2. 例子
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("吃")
def run(self):
print("跑")
def bark(self):
print("芜湖")
class cat(Animal):
def __init__(self, name, age, wight):
super().__init__(name, age)
# Animal.__init__(self, name, age) 效果一致
self.wight = wight
def cat(self):
print("cat")
def bark(self):
super().bark()
print("喵喵")
def __str__(self):
return ("{},{},{}".format(self.name, self.age, self.wight))
c = cat("cat", 1, 5)
c.run() # 跑
c.bark() # 芜湖 喵喵
print(c) # cat,1,5
2、多态
2.1、简介
以封装和继承为前提的基础上,不同的子类调用相同的方法,产生不同的结果。
前提:
- 多态发生在父类和子类之间
- 子类需要重写父类的方法
2.2、鸭子类型
在程序设计中,鸭子类型(英语:ducktyping)是动态类型的一种风格。
在这种风格中,一个对象有效的语义不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。“
鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。
2.3、示例
class Language:
def say(self):
print("调用的是 language 类的say方法")
class Python(Language):
def say(self):
print("调用的是 Python 类的say方法")
class Linux(Language):
def say(self):
print("调用的是 Linux 类的say方法")
a = Language()
a.say() # 调用的是 language 类的say方法
a = Python()
a.say() # 调用的是 Python 类的say方法
a = Linux()
a.say() # 调用的是 Linux 类的say方法
或者高级一点的用法
class Language:
def say(self):
print("调用的是 language 类的say方法")
class Python(Language):
def say(self):
print("调用的是 Python 类的say方法")
class Linux(Language):
def say(self):
print("调用的是 Linux 类的say方法")
def say(who):
who.say()
say(Language()) # 调用的是 language 类的say方法
say(Python()) # 调用的是 Python 类的say方法
say(Linux()) # 调用的是 Linux 类的say方法
3、封装
3.1、简介
封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式,使这些指隐藏的属性与方法无法在外部直接访问与调用,也无法被子类继承。
3.2、私有化属性
- 为了更好的保存属性安全,可以将属性定义为私有属性。
- 私有属性只能在类的内部被使用或修改。
- 在类的添加一个修改和访问的方法去维护私有属性。
1. 语法
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。
2.示例
class people:
__age = 18 # 私有属性
def __init__(self):
self.__name = '张三' # 私有属性
self.height = 178
def __str__(self):
# 私有化的属性能在内部使用
return '{}的身高是{}年龄是{}'.format(self.__name, self.height, self.__age)
def __set_name__(self, name):
self.__name = name
class student(people):
def __str__(self):
# 子类无法继承子类的私有属性
return '学生的身高是{}'.format(self.height, )
pass
zs = people()
print(zs) # 张三的身高是178年龄是18
zs.__set_name__("王五")
print(zs) # 王五的身高是178年龄是18
ls = student()
print(ls) # 学生的身高是178
3.3、私有化方法
私有化方法跟私有化属性概念一样,有些重要的方法。不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法。
1. 语法
两个下划线开头,声明该方法为私有,不能在类的外部被使用或直接调用。
2.示例
class people:
__age = 18 # 私有属性
def __init__(self):
self.__name = '张三' # 私有属性
self.height = 178
def __str__(self):
# 私有化的属性能在内部使用
return '{}的身高是{}年龄是{}'.format(self.__name, self.height, self.__age)
def __set_name__(self, name):
self.__name = name
def __hello(self): # 私有化方法
print("hello")
def sayHello(self):
self.__hello()
class student(people):
def __str__(self):
# 子类无法继承子类的私有属性
return '学生的身高是{}'.format(self.height, )
pass
ls = student()
ls.sayHello() # hello
3.4、property属性
通过property可以使私有属性依旧使用“类对象.属性”的方式进行操作。
1. 第一种方式
property属性方法:
- property(get方法,set方法,del方法(重置值))
- 三个传值可以根据需要只传一个或两个(为只读,可读可写)
class people:
__age = 18 # 私有属性
def __init__(self):
self.__name = '张三' # 私有属性
self.height = 178
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_age(self, age):
self.__age = age
def get_age(self):
return self.__age
age = property(get_age, set_age)
name = property(get_name, set_name)
p1 = people()
print(p1.age)
print(p1.name)
2. 方式二
使用注释方法:
- property需要在前,属性名.setter需要在后
- property是get,属性名.setter是set
- 方法名都为属性名
class people:
__age = 18 # 私有属性
def __init__(self):
self.__name = '张三' # 私有属性
self.height = 178
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
p1 = people()
print(p1.name) # 张三
p1.name = "李四"
print(p1.name) # 李四
print(p1.age) # 18
p1.age = 12
print(p1.age) # 12
4、小结
- 继承
- 多态
- 封装