序言:上个章节我们了解了面向对象的基础知识,这个章节我们将对面向对象的知识体系进行进一步的探究

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 (面向对象编程进阶)的更多相关文章

  1. Python集训营45天—Day03

    目录 1. 分支结构 1.1 初步介绍 1.2 使用案例 1.3 练习 2.循环结构 1.1 初步介绍 1.2 使用案例 1. 分支结构 1.1 初步介绍 至今,我们所写的Python代码都是顺序执行 ...

  2. Python集训营45天—Day01

    目录 1. Python简介 2. 第一个Python程序 3. 知识点梳理 序言:未来是数据的世界,而python 是一门可以高效简洁处理数据的语言,博主打算花45天左右完成python学习的从0到 ...

  3. Python集训营45天—Day02

    目录 变量和运算符 1.1 初步介绍 1.2 使用案例 1.3 知识点梳理 1.4 练习 序言:这一章我们将学习变量以及常见的类型,我们将以案例和代码相结合的方式进行梳理,但是其中所有的案例和知识点 ...

  4. Python集训营45天—Day04 (函数)

    目录 1. 函数介绍 2. 函数的参数 3. 模块与函数 4. 递归函数 5. 匿名函数 6. 多返回值 python 的学习已经进入到第四天,前面几章我们已经学会了基本的变量操作,以及分支结构和循环 ...

  5. Python集训营45天—Day08 (文件操作)

    目录 1. 文件操作介绍 2. 文件的读写 2.1 文本文件 2.2 二进制文件 2.3 JSON文件 3. 文件的定位,重命名和删除 4. 文件夹的相关操作 1. 文件操作介绍 大家应该听说过一句话 ...

  6. 进击的Python【第七章】:Python的高级应用(四)面向对象编程进阶

    Python的高级应用(三)面向对象编程进阶 本章学习要点: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 一.面向对象高级语法部分 静态方法 ...

  7. Day7 - Python基础7 面向对象编程进阶

    Python之路,Day7 - 面向对象编程进阶   本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个 ...

  8. python面向对象编程进阶

    python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...

  9. Python基础入门(6)- 面向对象编程

    1.初识面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本篇随笔将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象 ...

随机推荐

  1. .net必问的面试题系列之面向对象

    上个月离职了,这几天整理了一些常见的面试题,整理成一个系列给大家分享一下,机会是给有准备的人,面试造火箭,工作拧螺丝,不慌,共勉. 1.net必问的面试题系列之基本概念和语法 2.net必问的面试题系 ...

  2. Ajax前台返回JSON数据后再Controller中直接转换成类型使用,后台接收json转成实体的方法

    之前写过一篇记录文章,写的是将一个比较复杂的数据结构在前台组合起来后传递到后台. 当时并不太了解@RequestBody,也并没有使用js提供的JSON.stringify()方法 所有都是自己写的, ...

  3. 重读《学习JavaScript数据结构与算法-第三版》- 第6章 链表(一)

    定场诗 伤情最是晚凉天,憔悴厮人不堪言: 邀酒摧肠三杯醉.寻香惊梦五更寒. 钗头凤斜卿有泪,荼蘼花了我无缘: 小楼寂寞新雨月.也难如钩也难圆. 前言 本章为重读<学习JavaScript数据结构 ...

  4. 初探Electron,从入门到实践

    本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.   在开始之前,我想您一定会有这样的困惑:标题里的Electron ...

  5. Contour 学习笔记(一):使用 Contour 接管 Kubernetes 的南北流量

    原文链接:Contour 学习笔记(一):使用 Contour 接管 Kubernetes 的南北流量 在 Kubernetes 中运行大规模以 Web 为中心的工作负载,最关键的需求之一就是在 L7 ...

  6. Java 并发编程(一):摩拳擦掌

    这篇文章的标题原本叫做——Java 并发编程(一):简介,作者名叫小二.但我在接到投稿时觉得这标题不够新颖,不够吸引读者的眼球,就在发文的时候强行修改了标题(也不咋滴). 小二是一名 Java 程序员 ...

  7. spring加载bean流程解析

    spring作为目前我们开发的基础框架,每天的开发工作基本和他形影不离,作为管理bean的最经典.优秀的框架,它的复杂程度往往令人望而却步.不过作为朝夕相处的框架,我们必须得明白一个问题就是sprin ...

  8. python控制窗口口字形运动

    import win32con import win32gui import time import math notepad = win32gui.FindWindow("Photo_Li ...

  9. CodeForces 1082 D Maximum Diameter Graph

    题目传送门 题意:现在有n个点,每个点的度数最大为di,现在要求你构成一棵树,求直径最长. 题解:把所有度数为2的点先扣出来,这些就是这颗树的主干,也就是最长的距离. 然后我们把度数为2的点连起来,之 ...

  10. Spreading the Wealth uva 11300

    A Communist regime is trying to redistribute wealth in a village. They have have decided to sit ever ...