本系列文章回顾了 python大部分关键的知识点,关注那些容易被忽略的知识点。适用于有一定python基础的python学习者。
本系列文章主要参考廖雪峰的python学习网站。该学习网站内容全面,通俗易懂,强烈推荐初学者在这个网站学习python。

全系列:
(一)python基础
(二)函数
(三)高级特性
(四)函数式编程
(五)面向对象编程

文章目录

  • 面向对象编程
    • 类和实例
      • 数据封装
      • 其他
    • 访问限制
    • 继承和多态
    • 获取对象信息
      • type()
      • isinstance()
      • dir()
    • 实例属性和类属性

面向对象编程

数据封装、继承和多态是面向对象的三大特点。

类和实例

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

数据封装

每个实例拥有各自的数据,通过函数访问这些数据,从而将数据封装起来。

class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print('%s: %s' % (self.name, self.score))def get_grade(self):if self.score >= 90:return 'A'elif self.score >= 60:return 'B'else:return 'C'

“封装”的另一个好处是可以增加新的方法,比如get_grade。

其他

Python允许对实例变量绑定任何数据。
对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同。

>>> bart = Student('Bart Simpson', 59)
>>> lisa = Student('Lisa Simpson', 87)
>>> bart.age = 8
>>> bart.age
8
>>> lisa.age
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

访问限制

从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的name、score属性:

>>> bart = Student('Bart Simpson', 59)
>>> bart.score
59
>>> bart.score = 99
>>> bart.score
99

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef print_score(self):print('%s: %s' % (self.__name, self.__score))>>> bart = Student('Bart Simpson', 59)
>>> bart.__name
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'

这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

如果外部需要获取或修改name和score的值,可以增加get_name和get_score这样的方法。

class Student(object):...def get_name(self):return self.__namedef get_score(self):return self.__scoredef set_score(self, score):if 0 <= score <= 100:self.__score = scoreelse:raise ValueError('bad score')

在set_score函数中还可以进行参数检查,加强了程序的鲁棒性。

  • Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量。
    特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
  • 还有以单下划线开头的,如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问。
  • 双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:
>>> bart._Student__name
'Bart Simpson'

Python本身没有任何机制阻止你干坏事,一切全靠自觉。

>>> bart = Student('Bart Simpson', 59)
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name' # 设置__name变量!
>>> bart.__name
'New Name'

表面上看,外部代码“成功”地设置了__name变量,但实际上这个__name变量和class内部的__name变量不是一个变量!内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量

>>> bart.get_name() # get_name()内部返回self.__name
'Bart Simpson'

继承和多态

  • 继承可以获得父类的全部功能。继承可以增加自己的方法,也可以重写(覆盖)父类的方法。(python中的重写和重载:https://www.cnblogs.com/Hondsome/p/5962889.html)
  • 在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行。
  • 对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:
    调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

    • 对扩展开放:允许新增Animal子类;
    • 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
class Animal(object):def run(self):print('Animal is running...')class Dog(Animal):def run(self):print('Dog is running...')def eat(self):print('Eating meat...')class Cat(Animal):def run(self):print('Cat is running...')class Tortoise(Animal):def run(self):print('Tortoise is running slowly...')def run_twice(animal):animal.run()animal.run()# test
>>> run_twice(Dog())
Dog is running...
Dog is running...
>>> run_twice(Cat())
Cat is running...
Cat is running...
>>> run_twice(Tortoise())
Tortoise is running slowly...
Tortoise is running slowly...

获取对象信息

type()

判断对象类型,使用type()函数。

>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>

如何判断一个对象是否是函数?

>>> import types
>>> def fn():
...     pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True

isinstance()

对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

# 判断类和继承关系
>>> a = Animal()
>>> d = Dog()
>>> h = Husky()
>>> isinstance(h, Husky)
True
>>> isinstance(h, Dog)
True
>>> isinstance(h, Animal)
True
# 判断常见数据类型
>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True
# 判断一个变量是否是某些类型中的一种
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True

dir()

如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法。

>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:

>>> class MyObject(object):
...     def __init__(self):
...         self.x = 9
...     def power(self):
...         return self.x * self.x
...
>>> obj = MyObject()# 操作对象的属性
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404# 获得对象的方法
>>> hasattr(obj, 'power') # 有属性'power'吗?
True
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81

实例属性和类属性

类属性属于类所有,所有实例共享一个属性。

# 类属性
class Student(object):name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student

注意:
千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性

python学习--关注容易被忽略的知识点--(五)面向对象编程相关推荐

  1. python学习--关注容易被忽略的知识点--(四)函数式编程

    本系列文章回顾了 python大部分关键的知识点,关注那些容易被忽略的知识点.适用于有一定python基础的python学习者. 本系列文章主要参考廖雪峰的python学习网站.该学习网站内容全面,通 ...

  2. python学习--关注容易被忽略的知识点--(三)高级特性

    本系列文章回顾了 python大部分关键的知识点,关注那些容易被忽略的知识点.适用于有一定python基础的python学习者. 本系列文章主要参考廖雪峰的python学习网站.该学习网站内容全面,通 ...

  3. python学习--关注容易被忽略的知识点--(二)函数

    本系列文章回顾了 python大部分关键的知识点,关注那些容易被忽略的知识点.适用于有一定python基础的python学习者. 本系列文章主要参考廖雪峰的python学习网站.该学习网站内容全面,通 ...

  4. python学习--关注容易被忽略的知识点---(一)python基础

    本系列文章回顾了 python大部分关键的知识点,关注那些容易被忽略的知识点.适用于有一定python基础的python学习者. 本系列文章主要参考廖雪峰的python学习网站.该学习网站内容全面,通 ...

  5. python装饰器和异常处理_装饰器异常处理-面向对象编程-Python教程自动化开发_Python视频教程...

    课程目标:使学员掌握python基础教程知识,能够开发常用的PYTHON脚本 课程特色:实战,细致,生动,深入浅出 适用人群:适合PYTHON初学者 课程详情:该Python视频教程从0基础开始讲解P ...

  6. Dave Python 练习十五 -- 面向对象编程

    #encoding=utf-8 ### *************** 面向对象编程 ******************** #*********** Part 1: 面向对象编程 ******** ...

  7. c#和python同一主机直接udp_Python 第十一章:面向对象编程(上)!(系列发布)...

    Advanced Management Technology 前沿管理技术       共享知识智慧 Python语言经典课程 Python面向对象编程 本篇内容: 1.反射 2.面向对象编程 3.面 ...

  8. python类和对象介绍_Python开发基础-Day17面向对象编程介绍、类和对象

    面向对象变成介绍 面向过程编程 核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西.主要应用在一旦完成很少修改的地方,如linux ...

  9. python 二——函数、装饰器、生成器、面向对象编程(初级)

    本节内容 1.函数 2.装饰器 3.生成器 4.类 一.函数 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强... ...

最新文章

  1. Python监控目录文件夹,并使用SFTP上传目录及文件到linux服务器
  2. 自建ELK迁移阿里云日志服务
  3. [mybatis]缓存_缓存有关的设置以及属性
  4. ioc spring 上机案例_通过实例解析Spring Ioc项目实现过程
  5. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 24丨找到连续区间的开始和结束数字【难度中等】​
  6. 安卓应用安全指南 4.6.1 处理文件 示例代码
  7. 俄罗斯套娃(JOISC 2016 Day 1)
  8. 一个由于springboot自动配置所产生的问题的解决
  9. C#根据word模板生成word表格报表文档
  10. Yii Framework2.0开发教程(3)数据库mysql入门
  11. matlab除法不对,matlab中除法的使用,错误使用 / 矩阵维度必须一致
  12. vs2013 CodeLens
  13. 考研数学数学二有手就行系列之多元函数微分学(六)
  14. MYS-6ULX资料汇总
  15. abap --MOVE-CORRESPONDING
  16. 大厂面试题刷屏:一头牛重800kg,一座桥承重700kg,牛如何过桥?
  17. 永恒之蓝漏洞ms17-010
  18. CocosCreator之艺术数字资源 (LabelAtlas)
  19. 佛山 新型智慧城市建设实打实
  20. fish shell一个专为90后设计的命令行shell

热门文章

  1. 将先前的提交分成多个提交
  2. Git:git stash存储文件修改
  3. Android:解决Failed to load D:\Android-Studio\sdk\build-tools\xx.xx.xx\lib\dx.jar
  4. kali linux卸载lnmp,kali linux 如何安装lnmp 1.2
  5. 注册事件的两种方式(传统注册事件、方法监听注册事件)
  6. 什么是作用域链(源码解析)
  7. redis运行redis-server.exe错误
  8. 第十三章 线程安全与锁优化
  9. Ubuntu安装SublimeText3
  10. 一个工具类实现自定义Tablayout的下划线宽度