Python集训营45天—Day07 (面向对象编程进阶)
序言:上个章节我们了解了面向对象的基础知识,这个章节我们将对面向对象的知识体系进行进一步的探究
1. @property装饰器
上一章,我们在说属性的访问权限时,虽然我们不建议将属性设置为私有的,但是如果直接将属性直接暴露给外界也是有问题的,比如我们没办法检查赋给属性的值是否有效。我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的, 但是 校验属性的逻辑是在方法里的,我们没办法让其通过 实例.属性
进行赋值的时候 也去走我们 校验属性的那一套逻辑。如果我们想做到这一点,我们则需要使用 @property
装饰器来包装 getter 和 setter方法
# -*- coding:utf-8 -*-
"""
@Property 装饰器
version:0.1
author:coke
"""
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
#访问器
@property
def name(self):
return self.__name
#访问器 - getter方法
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
if age < 0 or age > 150:
print("年龄参数不正确")
return
self.__age = age
def play(self):
if self.__age <= 16:
print("%s正在玩飞行棋."%self.__name)
else:
print("%s正在玩斗地主."%self.__name)
def main():
person = Person("Jack",12)
person.age = -1
person.play()
if __name__ == "__main__":
main()
输出结果
总结:@property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性
2. 魔法方法
Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__
变量来进行限定。需要注意的是__slots__
的限定只对当前类的对象生效,对子类并不起任何作用。
# -*- coding:utf-8
"""
slots
version:0.1
author:coke
"""
class Person(object):
# 限定Person对象只能绑定_name,_age 和 _gender属性
__slots__ = ('_name', '_age', '_gender')
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print("%s正在玩飞行棋,年龄%d" % (self._name, self._age))
else:
print("%s正在玩斗地主,年龄%d" % (self._name, self._age))
def main():
person = Person("Jack",18)
person.play()
if __name__ == "__main__":
main()
总结:__slots__
变量,可以来限制该class实例能添加的属性.
3. 类属性和实例属性
在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是 类对象 所拥有的属性, 它被所有 类对象 的 实例对象 所共有,在内存中只存在一个副本 ,对于公有的类属性,在类外可以通过 类对象 和 实例对象 访问
类属性
class People(object):
address = "山东"
def __init__(self):
self.name = "xiaowang" #实例属性
self.age = 20
p = People()
p.age = 12
print(p.address) #正确
print(People.address) #正确
print(p.name) #正确
print(p.age) #正确
print(People.address)#正确
#print(People.age) #错误
#print(People.name) #错误
总结:实例属性,不能通过类对象.实例属性
获取,类属性 既可以通过 类对象.类属性
获取,也可以通过实例对象.类属性
获取
通过实例(对象)去修改类属性
class People(object):
country = 'china' #类属性
print(People.country) #china
p = People()
print(p.country) #china
p.country = "japan"
print(p.country) #japan
print(People.country) #china
del p.country
print(p.country) #china
总结:类属性 虽然可以通过 实例对象.类属性
访问,但是实例对象 无法对类属性进行修改和删除,若实例对象声明同名属性 则该属性属于 实例属性
4.静态方法和类方法
之前,我们在类中定义的方法都是对象方法,也就是说这些方法都是发送给对象的消息。实际上,我们写在类中的方法并不需要都是对象方法, 我们也可以根据需要创建 静态方法 和 类方法
静态方法
"""
静态方法
version:0.1
author:coke
"""
from math import sqrt
class Triangle(object):
def __init__(self,a,b,c):
self._a = a
self._b = b
self._c = c
@staticmethod
def is_valid(a,b,c):
return a + b > c and b + c > a and a + c > b
def perimeter(self):
return self._a + self._b + self._c
def area(self):
half = self.perimeter() / 2
return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c))
def main():
a,b,c = 3,4,5
if Triangle.is_valid(a,b,c):
t = Triangle(a,b,c)
print(t.perimeter())
print(t.area())
else:
print("无法构成三角形")
if __name__ == '__main__':
main()
总结:通过修饰器@staticmethod
来进行修饰 的方法,我们称其为静态方法,且静态方法可以通过类对象直接进行调用
类方法
"""
类方法
version:0.1
author:coke
"""
from time import time, localtime, sleep
class Clock(object):
def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second
@classmethod
def now(cls):
ctimes = localtime(time())
return cls(ctimes.tm_hour, ctimes.tm_min, ctimes.tm_sec)
def run(self):
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._hour += 1
self._minute = 0
if self._hour == 24:
self._hour = 0
def show(self):
return "%02d:%02d:%02d" % \
(self._hour,self._minute,self._second)
def main():
clock = Clock.now()
while True:
print(clock.show())
sleep(1)
clock.run()
if __name__ == "__main__":
main()
总结:用修饰器@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数 ,能够通过实例对象和类对象去访问 ,并且 由于已经获得 cls参数 等于间接获得了 类信息,所以我们也可以通过类方法创建一个 类对象
5. 单继承和多继承
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如下如所示:
单继承就是指 只继承一个父类信息,多继承则为 继承多个父类信息。要知道大部分程序语言 都只允许单继承,因为会出现钻石继承带来的问题。但是在python 中却意外的允许了 多继承的出现
单继承
# 继承object类父类信息
class Person(object):
"""人"""
def __init__(self,name,age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
def play(self):
print("%s正在愉快的玩耍."% self._name)
def watch_tv(self):
if self._age >= 18:
print("%s 正在看刺激的电影"%self._name)
else:
print("%s 正在看熊出没"%self._name)
# (person) 继承person父类信息
class Student(Person):
def __init__(self,name,age,grade):
super().__init__(name,age)
self._grade = grade
@property
def grade(self):
return self._grade
@grade.setter
def grade(self):
self._grade = grade
def study(self,course):
print("%s的%s正在学习%s."%(self._grade,self._name,course))
#继承 person父类信息
class Teacher(Person):
"""老师"""
def __init__(self,name,age,title):
super().__init__(name,age)
self._title = title
@property
def title(self):
return self._title
@title.setter
def title(self,title):
self._title = title
def teacher(self,course):
print("%s%s正在讲%s."%(self._name,self._title,course))
def main():
stu = Student("Jack",15,"初二")
stu.study("数学")
stu.watch_tv()
t = Teacher("Marry",38,"专家教授")
t.teacher("语文")
t.watch_tv()
if __name__ == "__main__":
main()
输出结果
多继承
#coding=utf-8
class base(object):
def test(self):
print('----base test----')
class A(base):
def test(self):
print('----A test----')
# 定义一个父类
class B(base):
def test(self):
print('----B test----')
# 定义一个子类,继承自A、B
class C(A,B):
pass
obj_C = C()
obj_C.test()
print(C.__mro__) #可以查看C类的对象搜索方法时的先后顺序
输出结果
总结:在出现钻石继承的问题时,调用谁,取决于 解析顺序(MRO)
6. 多态
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。
"""
多态
version:0.1
author:coke
"""
from abc import ABCMeta,abstractmethod
class Pet(object,metaclass=ABCMeta):
"""
宠物
"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' %self._nickname)
class Cat(Pet):
def make_voice(self):
print("%s:喵喵喵...." %self._nickname)
def main():
#利用多态性质进行不同的声音的输出
pets = [Dog('旺财'),Cat('凯迪'),Dog('索拉')]
for pet in pets:
pet.make_voice()
if __name__ == '__main__':
main()
解析:利用abc模块实现抽象类,abc.ABCMeta是实现抽象类的一个基础类, @abstractmethod
定义抽象方法,无需实现功能,子类继承抽象类必须重写 抽象类的抽象方法。抽象方法就像是个模板方法
7. del 方法
创建对象后,python解释器默认调用__init__()
方法;当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()
方法
import time
class Animal(object):
#初始化方法
#创建完对象后自动被调用
def __init__(self,name):
print("init方法被调用")
self.__name = name
#析构方法
#当对象被删除时,会自动被调用
def __del__(self):
print("del方法被调用")
print("%s对象马上被干掉了..."%self.__name)
dog = Animal("田园犬")
#删除对象
del dog
cat = Animal("波斯猫")
print("准备删除波斯猫了....")
del cat
输出结果
Python集训营45天—Day07 (面向对象编程进阶)的更多相关文章
- Python集训营45天—Day03
目录 1. 分支结构 1.1 初步介绍 1.2 使用案例 1.3 练习 2.循环结构 1.1 初步介绍 1.2 使用案例 1. 分支结构 1.1 初步介绍 至今,我们所写的Python代码都是顺序执行 ...
- Python集训营45天—Day01
目录 1. Python简介 2. 第一个Python程序 3. 知识点梳理 序言:未来是数据的世界,而python 是一门可以高效简洁处理数据的语言,博主打算花45天左右完成python学习的从0到 ...
- Python集训营45天—Day02
目录 变量和运算符 1.1 初步介绍 1.2 使用案例 1.3 知识点梳理 1.4 练习 序言:这一章我们将学习变量以及常见的类型,我们将以案例和代码相结合的方式进行梳理,但是其中所有的案例和知识点 ...
- Python集训营45天—Day04 (函数)
目录 1. 函数介绍 2. 函数的参数 3. 模块与函数 4. 递归函数 5. 匿名函数 6. 多返回值 python 的学习已经进入到第四天,前面几章我们已经学会了基本的变量操作,以及分支结构和循环 ...
- Python集训营45天—Day08 (文件操作)
目录 1. 文件操作介绍 2. 文件的读写 2.1 文本文件 2.2 二进制文件 2.3 JSON文件 3. 文件的定位,重命名和删除 4. 文件夹的相关操作 1. 文件操作介绍 大家应该听说过一句话 ...
- 进击的Python【第七章】:Python的高级应用(四)面向对象编程进阶
Python的高级应用(三)面向对象编程进阶 本章学习要点: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 一.面向对象高级语法部分 静态方法 ...
- Day7 - Python基础7 面向对象编程进阶
Python之路,Day7 - 面向对象编程进阶 本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个 ...
- python面向对象编程进阶
python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...
- Python基础入门(6)- 面向对象编程
1.初识面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本篇随笔将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象 ...
随机推荐
- REST 在 Java 中的使用
REST是一种混合的架构风格,它的由来以及它的架构元素在笔者的前一篇文章<REST 架构风格的由来 & 元素>中已经描述了.本篇主要描述一下J2EE对REST的支持. Java是在 ...
- 盘一盘 NIO (三)—— Selector解析
Selector是个啥? Selector是Java NIO核心组件中的选择器,用于检查一个或多个Channel(通道)的状态是否处于可读.可写.实现一个单独的线程可以管理多个channel,从而管理 ...
- 单元测试之NUnit三
NUnit 分三篇文章介绍,入门者可阅读文章,有基础者直接参考官方文档.初次写博客,望大家指点. 导航: 单元测试之NUnit一 单元测试之NUnit二 单元测试之NUnit三 除了Assert断言外 ...
- Vue入门到TodoList练手
学习资料 慕课网 - vue2.5入门 基础语法 示例代码1 <div id="root"> <h1>hello {{msg}}</h1> &l ...
- 开发APP必须知道的API集合,来源http://www.cnblogs.com/wikiki/p/7232388.html
笔记 OneNote - OneNote支持获取,复制,创建,更新,导入与导出笔记,支持为笔记添加多媒体内容,管理权限等.提供SDK和Demo. 为知笔记 - 为知笔记Windows客户端开放了大量的 ...
- BigDecimal 使用浅析
当参数单一时: 代码public class B { //BigDecimal函数测试类 public static void main(String agrs[]){ System.out.prin ...
- Filter(过滤器)(有待补充)
Filter(过滤器) 一.Filter(过滤器)简介 Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的 ...
- 计算机基础+python初阶
今日内容: 1.计算机基础知识 2.python简介 3.快速入门 今日内容: 一.计算机基础 1. 计算机什么组成的 输入输出设备 cpu 硬盘 内存 中央处理器 处理各种数据 相当于人的大脑 内存 ...
- Leetcode之深度优先搜索&回溯专题-638. 大礼包(Shopping Offers)
Leetcode之深度优先搜索&回溯专题-638. 大礼包(Shopping Offers) 深度优先搜索的解题详细介绍,点击 在LeetCode商店中, 有许多在售的物品. 然而,也有一些大 ...
- 计蒜客 ACM训练联盟周赛 第一场 Christina式方格取数 思维
助手Christina发明了一种方格取数的新玩法:在n*m的方格棋盘里,每个格子里写一个数.两个人轮流给格子染色,直到所有格子都染了色.在所有格子染色完后,计算双方的分数.对于任意两个相邻(即有公共边 ...