python学习之【继承、封装、多态】
后台-插件-广告管理-内容页头部广告(手机) |
#来评选你心中的TOP1编程语言#
前言
距离上篇文章 python学习之【类和对象】已有三个星期之久,这篇文章介绍 面向对象的三大特征——封装,继承,多态。
对于编程初学者来说,学习python应该是比较好入手的,文末会给大家介绍下python的一些特点,供需要学习编程语言的伙伴一个简单的参考。
我们知道python是一种面向对象的语言,面向对象的三大特征就是 封装,继承,多态。
封装
封装的目的
1:封装数据:保护隐私
2:封装方法:隔离复杂度(只保留部分接口对外使用)
封装的方式
1:公有属性和方法
公有属性和方法可以被类的外部访问和使用,不需要添加任何特殊符号。
2:私有属性和方法
以双下划线开头
封装属性: __attr 封装方法:__func- 1
- 2
在Python中,可以使用_和__来定义属性的访问级别。
以_开头的属性被视为受保护的属性,即它们不应该在类外部被直接访问。但是,它们可以在类的子类和内部方法中被访问。 以__开头的属性被视为私有属性,即它们不应该在类的外部被访问。但是,它们也可以在类的内部方法中被访问。- 1
- 2
- 3
这里要提一下,对于python中受保护的属性,python是不会对其做任何处理的,比如我们看下面这个例子:
但是按照python中的规则来讲,我们不能在类外部访问类内受保护的属性或方法。
还是这个例子,我们如果在类外访问私有属性,会发生什么呢?
我们看到,对于私有属性,如果我们要在类外进行访问的话,会抛出 AttributeError 的错误。
3:属性装饰器和方法装饰器
属性装饰器是一种特殊的函数,它可以被用来修改属性的访问方式。在Python中,我们可以使用@property 和 @属性名.setter装饰器来定义属性的访问器和修改器。
@property装饰器用于定义属性的访问器,它会将属性定义为一个只读属性。当外部代码试图修改这个属性时,会触发一个AttributeError异常。
@属性名.setter装饰器用于定义属性的修改器,它可以让外部代码修改这个属性的值。当外部代码试图读取这个属性时,会触发一个AttributeError异常。
方法装饰器
方法装饰器是用来装饰类的方法的,它的作用是在不改变原方法定义的情况下,为方法添加一些额外的功能,比如权限检查、缓存等。
常见的方法装饰器有静态装饰器 @staticmethod;类方法装饰器 @classmethod
下面为大家详细介绍下私有属性和方法的封装方式,python中的装饰器会另起一篇文章介绍。
封装的实现
封装属性
#封装age属性 class Student: def __init__(self,name,age): self.name=name self.__age=age #不希望age在类外部被使用 # 使age可以在类内部被调用 def show(self): print('我的名字:',self.name,';我的年龄:',self.__age) stu=Student('tom',10) stu.show() #我的名字: tom ;我的年龄: 10 # 在类外调用name 和 age print('我的名字:',stu.name) #我的名字: tom print('我的年龄:',stu.age) #出现报错AttributeError: 'Student' object has no attribute 'age'- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
那应该如何调用这个封装的属性age呢,这里我们可以引入一个dir()查看实例对象可使用的方法属性:
print('实例对象stu可以使用的方法属性有:',dir(stu)) #包含 _Student__age print('我的年龄是:',stu._Student__age)- 1
- 2
封装方法
和封装属性类似,在类内部需要封装的方法前面加上双下划线 “__”
同样的,如果我们要调用封装后的方法,应该如何做:
class Student: def __init__(self,name,age): self.name=name self.__age=age #不希望age在类外部被使用 # 使age可以在类内部被调用 def __show(self): print('我的名字:',self.name,';我的年龄:',self.__age) stu=Student('tom',10) stu._Student__show()- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
由此可见:
Python 的封装并不是真正意义上的外部无法调用,与java ,PHP等语言不同,Python若调用封装的属性或方法,需要在方法和属性前加_类名。
那么既然python中的属性和方法被封装后依然可以被调用,那么封装的意义又何在呢?
封装的目的是隐藏类的实现细节,只暴露必要的接口给外部使用。如果一个属性或方法被公开为可访问的,那么它将变得容易受到攻击和滥用。例如,如果一个类的__init__()方法可以接受任意数量的参数,那么任何人都可以构造恶意对象并调用该方法。
通过将属性或方法定义为私有,我们可以确保只有类内部的对象才能访问它们。这有助于保护类的实现细节,防止不必要的干扰和错误。此外,封装还有助于提高代码的可维护性和可重用性,因为它可以将类的实现细节隐藏起来,使代码更加清晰和易于理解。
父类与子类的封装
子类的封装属性以及方法不会覆盖父类的封装属性或方法
# 子类封装的方法或属性不会覆盖父类的方法或属性 class A: __name = 'A' # 变形为_A__name def get_x(self): print('父类A:',self.__name) class A1(A): # A1 继承了 A 的方法和属性 __name='我是父类A的子类A1' #变形为_A1__name def __say(self): print('这是子类A1的实例方法') # A1的实例对象 obj = A1() # 调用父类A的实例方法 obj.get_x() #父类: A- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
小结
通过以上的例子我们得出:
类的封装不是真正意义上的“私有化”,而是一个语法上的变形 类的封装属性或方式,其实在定义阶段就已经进行了语法上的变形 类的调用阶段,再进行封装语法已经没有任何用处了- 1
- 2
- 3
继承
继承的含义
python中的继承机制经常用于创建和现有类功能类似的新类,又或是新类只需要在现有类基础上添加一些成员(属性和方法),但又不想直接将现有类代码复制给新类。也就是说,当我们需要进行类的重复使用时,就可以使用这种继承机制来实现。
继承的实现
Python 中,实现继承的类称为子类,被继承的类称为父类;
子类继承父类时,只需在定义子类时,将父类(可以是多个)放在子类之后的圆括号里即可:
class 类名(父类1, 父类2, ...): #类定义部分- 1
- 2
python中如果类没有指定继承某个类,那么就默认继承的是object类,我们看这个例子:
# 编写Person类,以及继承Person类的两个子类Student和Teacher class Person(object): def __init__(self,name,age): self.name=name self.age=age def info(self): print('姓名:',self.name,'年龄:',self.age) # Student类 class Student(Person): def __init__(self,name,age,stu_no): super().__init__(name,age) self.stu_no=stu_no # Teacher 类 class Teacher(Person): def __init__(self,name,age,teach_year): super().__init__(name,age) self.teach_year=teach_year # 创建学生对象和教师对象 stu1=Student('小明',17,1001) teacher1=Teacher('张丽',30,6) stu1.info() teacher1.info() ''' 姓名: 小明 年龄: 17 姓名: 张丽 年龄: 30 '''- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
这个例子的继承关系并不复杂,定义一个Person类,没有指定继承某个类默认继承object类(object 类是 Python 中所有类的父类,即要么是直接父类,要么是间接父类);然后定义Person类的两个子类:Student类和Teacher类,分别继承Person类。
方法重写
如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写;子类重写后的方法中可以通过super().xxx() 调用父类中被重写的方法:
class Person(object): def __init__(self,name,age): self.name=name self.age=age def info(self): print('名字:',self.name,'年龄:',self.age) class Student(Person): def __init__(self,name,age,stu_no): super().__init__(name,age) self.stu_no=stu_no #方法重写 def info(self): super().info() #调用父类的info() print('学号是:',self.stu_no) class Teacher(Person): def __init__(self,name,age,teach_year): super().__init__(name,age) self.teach_year=teach_year #方法重写 def info(self): super().info()#调用父类的info() print('教龄是:',self.teach_year) stu1=Student('小华',17,1001) teacher1=Teacher('赵丽',40,10) stu1.info() ''' 名字: 小华 年龄: 17 学号是: 1001 ''' print('\n---------------教职工-------------\n') teacher1.info() ''' 名字: 赵丽 年龄: 40 教龄是: 10 '''- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
如果一个类是空类,但是继承了含有方法和属性的类,那么这个类也同样含有父类的方法和属性:
class People: def __init__(self,name): self.name =name def say(self): print("People类",self.name) class Animal: def __init__(self): self.name = Animal def say(self): print("Animal类",self.name) #People类是Person父类中最近的父类,因此People中的name属性和say()方法会遮蔽 Animal 类中的 class Person(People, Animal): pass zhangsan=Person('张三') zhangsan.say() # People类 张三- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
可以看到,当 Person 同时继承 People 类和 Animal 类时,People 类在前,因此如果 People 和 Animal 拥有同名的类方法,实际调用的是 People 类中的;由此也可以看出,python支持多继承。
object类
前面我们提到:object类是所有类的父类 ,因此所有类都有object类的属性和方法,这里我们再了解一下有关此类的一些方法。
1:内置函数 dir()可以查看指定对象所有的属性
2:object有一个__str__()方法,用于返回一个对于对象的描述 , 对应于内置函数str()经常用于print()方法,帮我们查看对象的信息 所以我们经常会对__str__()进行重写。
内置函数dir()
str()方法
# 定义方法再输出实例对象 class Student(): def __init__(self,name,age): self.name=name self.age=age # 进行方法重写 def __str__(self): return '名字是{},年龄是{}'.format(self.name,self.age) #格式化字符串 stu=Student('luky',18) print(stu,type(stu)) #默认调用__str__()方法,返回的类型就是该方法的内容 # 名字是luky,年龄是18- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
多态
python是一种动态语言,其最明显的特征就是在使用变量时,无需为其指定具体的数据类型。这会导致一种情况,即同一变量可能会被先后赋值不同的类对象。
class Animal: def say(self): print("赋值的是Animal类的实例对象") class Plant: def say(self): print("赋值的是Plant类的实例对象") a = Animal() a.say() # 赋值的是Animal类的实例对象 a = Plant() a.say() # 赋值的是Plant类的实例对象- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
在这个例子中我们看到a 可以被先后赋值为Animal类和Plant类的对象,但这并不是多态。类的多态特性,还要满足以下 2 个前提条件:
1:继承:多态一定是发生在子类和父类之间;
2:重写:子类重写了父类的方法。
但python作为一种动态语言不需要关心该类的继承关系 ,只需要关心该类中是否定义了某些属性方法,我们对上面的例子再进行编写:
class Animal: def say(self): print("调用的是 Animal 类的say方法") class Plant(Animal): def say(self): print("调用的是 Plant 类的say方法") class People(Animal): def say(self): print("调用的是 People类的say方法") a = Animal() a.say() # 调用的是 Animal 类的say方法 a = Plant() a.say() # 调用的是 Plant 类的say方法 a = People() a.say() # 调用的是 People类的say方法- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
可以看到,Plant类和People都继承Animal类,且各自都重写了父类的 say() 方法。从运行结果可以看出,同一变量 a 在执行同一个 say() 方法时,由于 a 实际表示不同的类的实例对象,因此 a.say() 调用的并不是同一个类中的 say() 方法,这就是多态。
我们也可以在类外定义一个函数,通过不同类的实例对象对这一函数的调用,动态的决定调用哪个对象的方法:
class Flower: def color(self): print('花是五颜六色的') class Rose(Flower): def color(self): print('玫瑰是红色的') class Moli(Flower): def color(self): print('茉莉是白的的') class Plant: def color(self): print('花属于植物') # 定义一个函数 def fun(obj): obj.color() # 调用函数 fun(Flower()) #花是五颜六色的 fun(Rose()) #玫瑰是红色的 fun(Moli()) #茉莉是白的的 print('-----------无任何继承关系的植物类-------\n') fun(Plant()) #花属于植物 虽然植物类和其他定义了的类无继承关系,但是在该类中定义了color实例方法,因此会在调用时执行该方法- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
由此:
多态可以简单理解为:具有多种形态 ,它指的是即便不知道一个变量所引用的对象到底是什么类型, 仍然可以通过这个变量调用方法; 在运行过程中根据变量所引用的对象的类型 , 动态的决定调用哪个对象中的方法。
关于python
Python是一种高级编程语言,被广泛应用于各种不同的领域,包括软件开发、数据科学、网络编程和人工智能等。Python有许多特性,包括易于学习、语法简单、动态类型、面向对象的设计、模块化编程、可移植性和广泛的第三方库支持。
对于初学者
对于编程初学者来说,python的可读性较强,主要有以下几个方面:
1:python使用缩进来代表一个代码块,这样也会使代码层次更加鲜明,方便查阅;
2:python的语法较为简单,很多关键字见名知意
同时python拥有强大的第三方库支持,我们可以直接调用这些库,极大提高了我们的开发效率。
用到的工具
最常用的python编辑器就是pycharm
大家可以自行去网上查找安装教程,这里我把我在安装过程中出现的一个路径问题提一下,希望可以提供些帮助:
如果我们在安装pycharm的过程中显示不出运行结果,那基本上就是python的解释器文件路径没有放到pycharm 编辑器中,解决方式如下:
首先找到python的解释器路径:
可以使用Windows命令行输入where python
也可以直接在资源管理器上查找python.exe:
然后将python.exe的路径复制下来,打开pycharm:
最后将路径添加到pycharm的Base interpreter中,重启pycharm即可:
如何去学
python虽然入门比较简单,但是和其他的编程语言一样,只有实践才能出真知。书本上的讲解比较晦涩,我们可以通过在网上找一些视频资源看(比如B站上的python教程,大家择优选择),并且在看的同时一定一定要自己动手敲出来,无论学习什么语言都是需要自己亲自动手操作的,只有在操作时不断发现bug,然后利用身边的资源去解决bug,出现bug时我们可以将报错信息直接粘到浏览器,由于每个人的报错原因都不尽相同,因此我们要多尝试,多思考。再者,我们可以将我们的程序中报错的代码块直接放到GitHub上,去查询是否有相似的报错解决方式,又或者我们去询问chatgpt,是否有解决方法等等。方正就是——只要思想不滑坡,方法总比困难多!
另外就是多刷题,比如可以去牛客网找题刷,尽量尝试先思考,然后在编辑器上根据自己的思路去作答,如果运行失败,一定要自己亲手调试分析下,这个过程很重要,也是举一反三的关键。
每篇一语
星光不负赶路人!
如有不足,感谢指正!
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |