目录

面向对象高级编程

__slots__

@property

定制类

使用枚举类

使用元类


面向对象高级编程

__slots__

  1. 在上一篇文章讲到过,我们可以通过简单的操作就能够给实例或类绑定属性。这里我们来讨论如何给实例和类绑定方法,先来看个例子:

    from types import MethodTypeclass Dog():def __init__(self, name):self.Name = namedef show(self):print('my name\'s %s' % self.Name)d = Dog('Dolly')

    需要注意的是:若是通过下面这种方式给实例绑定方法则在调用方法时,解释器就不会自动把本实例作为一个参数传入self中了,也就是不会将实例和方法进行绑定

    In [2]: d.show = showIn [3]: d.show()
    Traceback (most recent call last):File "<ipython-input-3-73a424ac9a82>", line 1, in <module>d.show()TypeError: show() missing 1 required positional argument: 'self'

    正确的绑定操作应该是这样:

    In [5]: d.show = MethodType(show, d) #通过MethodType函数给实例d绑定方法In [6]: d.show() #调用刚刚绑定的方法
    my name's Dolly

    从例子中可以看到,我们通过MethodType函数来给实例绑定方法。这里我们仅仅是给实例d绑定了show方法,也就是说其它的实例并没有show方法:

    In [8]: d2 = Dog('Mike')In [9]: d2.show()
    Traceback (most recent call last):File "<ipython-input-9-714779789114>", line 1, in <module>d2.show()AttributeError: 'Dog' object has no attribute 'show'

    为了解决这个问题,我们可以尝试给类绑定方法,因为类的方法是所有实例所共有的,给类绑定方法非常简单:

    In [10]: def bark(self):...:     print('wang wang wang !')...:     In [11]: Dog.bark = bark

    现在我们来试试:

    In [12]: d.bark()
    wang wang wang !In [13]: d2.bark()
    wang wang wang !
  2. 有时我们想给实例绑定的属性添加一个限定,使得属性的绑定不能是任意的,而只能绑定我们规定的几种属性。这就要使用一个特殊的变量——__slots__:
    class  Dog():__slots__ = ('name', 'gender') #限定Dog的实例只能够绑定name和gender这两个属性

    现在我们来试试给实例绑定属性:

    In [2]: d = Dog()In [3]: d.name = 'Dolly' #给d绑定name属性In [4]: d.name
    Out[4]: 'Dolly'In [5]: d.gender = 'femal' #给d绑定gender属性In [6]: d.gender
    Out[6]: 'femal'In [7]: d.color = 'yello' #给d绑定color属性
    Traceback (most recent call last):File "<ipython-input-7-dd28abd9292c>", line 1, in <module>d.color = 'yello'AttributeError: 'Dog' object has no attribute 'color'

    我们看到在给实例d绑定name和gender这两个属性时没问题,在绑定属性color时就抛出了错误,因为color这个属性是不被允许的!如果再定义一个Dog的子类Husky,并且Husky类中没有对__slots__进行声明,那么Husky的实例对属性的绑定是不受其父类Dog影响的,可以任意绑定;如果Husky中对__slots__也进行了声明,那么Husky实例所允许绑定的属性是两个声明的__slots__属性之和

@property

  1. 通过对前面知识的学习,我们在给实例绑定属性时一般进行类似以下操作:

    In [13]: class Dog():...:     def __init__(self, name):...:         self._name = name #绑定属性_name...:     In [14]: d = Dog('Dolly')In [16]: d.age = 999999 #绑定属性age

    但是这样会产生的一个问题是:如果没有任何措施加以限制的话,属性值是可以改成任意值的,就比如上述例子中将age设为999999,这明显不符合实际!也许我们可以定义一个set_age()方法用于修改属性值,在方法中对属性的取值加以限制:

    class Dog():def get_age(self):return self.agedef set_age(self, val):if not isinstance(val, int): #检查val的类型raise ValueError('年龄只能为整数!')elif val < 0 or val > 30: #检查val的取值raise ValueError('年龄只能在0~30之间!')self.age = val

    现在我们来试试:

    In [18]: d = Dog()In [19]: d.set_age('六岁')
    Traceback (most recent call last):File "<ipython-input-19-8626661de8b1>", line 1, in <module>d.set_age('六岁')File "C:/Users/Whisky/.spyder-py3/temp.py", line 10, in set_ageraise ValueError('年龄只能为整数!')ValueError: 年龄只能为整数!In [20]: d.set_age(35)
    Traceback (most recent call last):File "<ipython-input-20-b611f54c4999>", line 1, in <module>d.set_age(35)File "C:/Users/Whisky/.spyder-py3/temp.py", line 12, in set_ageraise ValueError('年龄只能在0~30之间!')ValueError: 年龄只能在0~30之间!In [21]: d.set_age(6)In [22]: d.get_age()
    Out[22]: 6

    其实心细的同学会发现这没从根本上解决问题,我们还是可以随意更改age的值,只要不通过调用set_age()方法就行了:

    In [24]: d.age = 100In [25]: d.age
    Out[25]: 100

    那么到底怎么解决这个问题呢?这就要使用Pyhton提供的@property装饰器了!先来看下面的例子:

    class Dog():@propertydef age(self):return self._age ##这里不要写成self.age@age.setterdef age(self, val):if not isinstance(val, int):raise ValueError('年龄必须为整数值!')elif val < 0 or val > 30:raise ValueError('年龄只能在0~30间')self._age = val ##这里不要写成self.age = val

    Python内置的@property装饰器能够把方法转成属性的调用,而另一个装饰器@age.setter能够把方法转成属性的赋值,来看下怎么使用:

    In [21]: d = Dog()In [22]: d.age = 6 #实际上是转化为d.set_age(6)In [23]: d.age #实际上是转化为d.get_age()
    Out[23]: 6In [27]: d.age = 999 #实际上是转化为d.set_age(999)
    Traceback (most recent call last):File "<ipython-input-27-8e0eec63a531>", line 1, in <module>d.age = 999File "C:/Users/Whisky/.spyder-py3/temp.py", line 14, in ageraise ValueError('年龄只能在0~30间')ValueError: 年龄只能在0~30间

    我们看到,在使用d.age = 999对age的值进行修改时,实际上是转化为执行d.set_age(999),而999是age不能接受的取值故抛出错误。_在两个方法中我们使用的属性是_age而非age,其实将_age改成其他的名字也行,但就是不能写成和age一样!!!自己试试看会出现什么情况!这实际上是给属性age取了个别名_age,试试看直接访问_age会是什么结果:

    In [24]: d._age
    Out[24]: 6In [25]: d._age = 999In [26]: d.age
    Out[26]: 999

    可以看到,我们其实还是可以直接修改age,你非要给age胡乱的设值也没办法,所以只能要求你遵守编程规范,按规矩办事

    (XWZ)的Python学习笔记Ⅲ——面向对象高级编程相关推荐

    1. Python学习之面向对象高级编程

      Python学习目录 1. 在Mac下使用Python3 2. Python学习之数据类型 3. Python学习之函数 4. Python学习之高级特性 5. Python学习之函数式编程 6. P ...

    2. Python学习笔记三之编程练习:循环、迭代器与函数

      Python学习笔记三之编程练习 1. 编程第一步 # 求解斐波纳契数列 #/user/bin/python3#Fibonacci series:斐波那契数列 #两个元素的总和确定了下一个数 a,b= ...

    3. Python学习笔记·交互式图形编程

      Python学习笔记·交互式图形编程 注:在校计算机学生一名,菜鸟一枚,最近开始学习Python的基础知识希望有什么不对的地方各位大佬能够不令赐教! 课程是在中国大学MOOC上学的,有兴趣的同学可以自 ...

    4. Python学习笔记:Io编程序列化

      前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

    5. Python学习笔记:IO编程StringIO和BytesIO

      前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

    6. Python基础之六面向对象高级编程

      '''面向对象高级编程 ''' from enum import Enum'''__slots__限制实例属性定义的属性只对当前类实例起作用,对于继承的子类不起作用''' class Student( ...

    7. Python学习笔记:高级特性

      前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

    8. 【廖雪峰Python学习笔记】函数式编程

      Functional Programming 高阶函数 返回函数 匿名函数 装饰器 偏函数 高阶函数 面向过程的程序设计: 把大段代码拆成函数,通过一层层函数调用,可将复杂任务分解成若干简单的任务 函 ...

    9. 侯捷C++学习记录-面向对象高级编程上

      目标: 培养正规的.大气的编程习惯 以良好的方式编写C++ class [Object Based(基于对象)] 学习Classes 之间的关系 [Object Oriented(面向对象)] 继承( ...

    10. 廖雪峰python学习笔记之高级特性

      写在前面 寒假时本科舍友的一句话点醒梦中人-你的python基础还没弄明白吧!猛地一想好像确实如此,还停留在随插随用的程度,并且对于迭代器,函数式编程等等,没有深刻理解,所以项目做起来也是空中楼阁,所 ...

    最新文章

    1. mysql 返回最大值列名_多列求最大值列和列名
    2. 【精华】Linux用户Hive权限控制实践
    3. 咏南新CS三层开发框架
    4. 计算机组成原理课后习题答案一
    5. Java结合POI清洗Excel
    6. Python MySQLdb 循环插入execute与批量插入executemany性能分析(list批量写法亲测成功)
    7. php 一天只能点赞上一次,ThinkPHP3.2 实现浏览量和点赞量,每次访问页面浏览量+1以及每个登录用户只能对同一篇文章点赞一次-Go语言中文社区...
    8. 如何使用SAP CRM Marketing Survey创建一个市场问卷调查
    9. 应用的大数据:医疗保健的经济学
    10. “杀死” APP 的留白设计!
    11. ARM926EJ-S/ARM920T 协处理器 CP14, CP15详解
    12. 加入收藏与设为首页代码(兼容各种浏览器)
    13. 零基础java自学流程-Java语言高级531
    14. kali-beef工具(xss-stored)
    15. 2021年PMP考试模拟题5(含答案解析)
    16. 稻盛和夫—《活法》读后感
    17. 阿里成立达摩院,三年投入超千亿
    18. Windows10 CMD SSH登陆不了服务器出现 WARNING: REMOTE HOST
    19. vue模板语法是什么?
    20. UMLChina建模竞赛第3赛季第10轮:汽车、EA

    热门文章

    1. 基于SSM+SpringBoot+Thymeleaf+LayUI的高校大学生成绩分析管理系统(附论文)
    2. 移动前端开发和web前端开发有什么区别
    3. 2.遥感传感器和遥感数据
    4. 在一张图片的某个特定位置添加另外一张图片
    5. (一) Windows环境下的Detours编译
    6. php实现微信小程序登录(根据微信小程序接口更新最新教程)
    7. 几款连接redis的客户端(GUI客户端),下面记录了我使用的几款
    8. 测绘类(遥感)投稿期刊(卓越期刊、EI、CSCD、核心期刊)汇总,内附投稿链接
    9. php工具箱升级MySQL
    10. 雪球: 关于股票的经典书籍有哪些推荐