面向对象进阶 三大特性
一、类方法、静态方法
1. 类方法
- 第一个形参是类对象的方法
- 需要用装饰器
@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数。
class Dog(object):__type = "狗"# 类方法,用classmethod来进行修饰@classmethoddef get_type(cls):return cls.__type
print(Dog.get_type())
使用场景:
- 当方法中 需要使用类对象 (如访问私有类属性等)时,定义类方法
- 类方法一般和类属性配合使用
2. 静态方法
- 需要通过装饰器
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。 - 静态方法 也能够通过 实例对象 和 类对象 去访问。
class Dog(object):type = "狗"def __init__(self):name = None# 静态方法 @staticmethoddef introduce(): # 静态方法不会自动传递实例对象和类对象print("犬科哺乳动物,属于食肉目..")dog1 = Dog()
Dog.introduce() # 可以用 实例对象 来调用 静态方法
dog1.introduce() # 可以用 类对象 来调用 静态方法
使用场景:
- 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
注意点:
- 类中定义了同名的方法时,调用方法会执行最后定义的方法
class Dog:def demo_method(self):print("对象方法")@classmethoddef demo_method(cls):print("类方法")@staticmethoddef demo_method(): # 被最后定义print("静态方法")dog1 = Dog()
Dog.demo_method() # 结果: 静态方法
dog1.demo_method() # 结果: 静态方法
__new__和__init__方法
class A(object):def __init__(self):print("这是 init 方法")def __new__(cls):print("这是 new 方法")return object.__new__(cls)A()
总结
__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以return父类__new__
出来的实例,或者直接是object的__new__
出来的实例__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值
二、单例设计模式
举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。
# 实例化一个单例
class Singleton(object):__instance = None__is_first = Truedef __new__(cls, age, name):if not cls.__instance:cls.__instance = object.__new__(cls)return cls.__instancedef __init__(self, age, name):if self. __is_first: # 不会再创建第二个对象self.age = ageself.name = nameSingleton. __is_first = Falsea = Singleton(18, "张三")
b = Singleton(28, "张三")print(id(a))
print(id(b))print(a.age) # 18
print(b.age) # 18a.age = 19
print(b.age)
三、继承的基本使用
在现实生活中,继承一般指的是子女继承父辈的财产,父辈有的财产,子女能够直接使用。
程序里的继承
继承是面向对象软件设计中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
- 在程序中,继承描述的是多个类之间的所属关系。
- 如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。
- 那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。
class Animal:def __int__(self):pass"""动物类"""def sleep(self):print('正在睡觉')class Dog(Animal):"""Dog类继承自Animal类"""def __init__(self):passclass Cat(Animal): # 定义类时,在括号后面传入父类的类名,表示子类继承父类"""Cat类继承自Animal类"""def __int__(self):pass# Dog 和 Cat 都继承自Animal类,可以直接使用Animal类里的sleep方法
dog = Dog()
dog.sleep()cat = Cat()
cat.sleep()
在Python中,继承可以分为单继承、多继承和多层继承。
单继承:子类只继承一个父类
继承概念:子类用于父类的所有的方法和属性。
继承语法:
class 类名(父类名):pass
- 子类继承自父类,可以享受父类中已经封装好的方法,不需要再次定义
- 子类中应该根据职责,封装子类特有的属性和方法。
继承的传递性
Dog类继承自Animal,XiaoTianQuan又继承自Dog类,那么XiaoTianQuan类就具有了Animal类里的所有属性和方法。
子类拥有父类以及父类的父类中封装的所有属性和方法。
多继承
子类可以拥有多个父类,并且具有所有父类的属性和方法。
语法格式:
class 子类名(父类名1,父类名2...)pass
多继承的使用注意事项
如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪个父类的方法?
说明:开发中,应该尽量避免这种容易产生混淆的情况。如果多个父类之间存在同名的属性后者方法,应该尽量避免使用多继承。
Python中的MRO
- Python中针对类提供了一个内置属性
__mro__
可以用来查看方法的搜索顺序。 - MRO 是
method resolution order
的简称,主要用于在多继承时判断方法属性的调用顺序。
print(C.__mro__)
输出结果:
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
- 在调用方法时,按照
__mro__
的输出结果从左至右的顺序查找。 - 如果再当前类中找到方法,就直接执行,不再向下搜索。
- 如果没有找到,就顺序查找下一个类中是否有对应的方法,如果找到,就直接执行,不再继续向下搜索。
- 如果找到了最后一个类,依然没有找到方法,程序就会报错。
新式类和旧式(经典)类
object
是Python中所有对象的基类,提供了一些内置的属性和方法,可以时候用dir
函数查看。
- 新式类:以
object
为基类的类,推荐使用 - 经典类:不以object为基类的类,不推荐使用
- 在 Python3.x 以后定义类时,如果没有指定父类,这个类会默认继承自 object,所以,python3.x版本定义的类都是新式类。
- 在Python2.x中定义类时,如果没有指定父类,则不会继承自object.
为了保证代码在Python2.x和Python3.x中都能够运行,在定义类时,如果一个类没有父类,建议统一继承自'object'
class 类名(object):pass
四、对象相关的内置函数
Python中的身份运算符用来判断两个对象是否相等;isinstance用来判断对象和类之间的关系;issublcass用啊里判断类与类之间的关系。
身份运算符
身份运算符用来比较两个对象的内存地址,看这两个对象是否是同一个对象。
class Person(object):def __init__(self, name, age):self.name = nameself.age = agep1 = Person('张三', 18)
p2 = Person('张三', 18)
p3 = p1print(p1 is p2) # False
print(p1 is p3) # True
isinstance
instance内置函数,用来判断一个实例对象是否是由某一个类(或者它的子类)实例化创建出来的。
class Person(object):def __init__(self, name, age):self.name = nameself.age = ageclass Student(Person):def __init__(self, name, age, score):super(Student, self).__init__(name, age)self.score = scoreclass Dog(object):def __init__(self, name, color):self.name = nameself.color = colorp = Person('tony', 18)
s = Student('jack', 20, 90)
d = Dog('旺财', '白色')print(isinstance(p, Person)) # True.对象p是由Person类创建出来的
print(isinstance(s, Person)) # True.对象s是有Person类的子类创建出来的
print(isinstance(d, Person)) # False.对象d和Person类没有关系
issubclass
issubclass 用来判断两个类之间的继承关系。
class Person(object):def __init__(self, name, age):self.name = nameself.age = ageclass Student(Person):def __init__(self, name, age, score):super(Student, self).__init__(name, age)self.score = scoreclass Dog(object):def __init__(self, name, color):self.name = nameself.color = colorprint(issubclass(Student, Person)) # True
print(issubclass(Dog, Person)) # False
五、多态
面向对象的三大特性:
- 封装:这是定义类的准则,根据对象的特点,将行为和属性抽象出来,封装到一个类中。
- 继承:这是设计类的技巧。父类与子类,主要体现在代码的重用,不需要大量的编写重复代码。
- 多态:不同的子类调用相同的父类方法,产生不同的执行结果,可以增加代码的外部灵活度。多态是以继承和重写父类方法为前提的,它是一种调用方法的技巧,不会影响到类的内部设计。
场景
- 提供三个类:缉毒犬、军犬、人
- 缉毒犬-->追查毒品,军犬-->攻击假人,人-->让小狗干活
- 设计类来完成功能。
代码实现:
class ArmyDog(object):def bite_enemy(self):print('追击敌人')class DrugDog(object):def track_drug(self):print('追查毒品')class Person(object):def work_with_army(self, dog):dog.bite_enemy()def work_with_drug(self, dog):dog.track_drug()ad = ArmyDog()
dd = DrugDog()p = Person()
p.work_with_army(ad)
p.work_with_drug(dd)
思考:这段代码设是否有问题?
新增需求:此时,又多了一个犬种,就又需要在Person类里新建一个方法,让这个方法操作新的狗。
class XiaoTianDog(object):def eat_moon(self):print('哮天犬把月亮吃了')class Person(object):def work_with_xiaotian(self, dog): # 添加方法dog.eat_moon()
Person 类总是不断的添加新的功能,每次都需要改动Person类的源码,程序的扩展性太差了!
- 最好是提供一个父类 Dog,具备 work 的功能,其他小狗继承它,这样只要是小狗类,则行为被统一起来了,我们人类完全可以保证,只要是小狗的子类,找它干活肯定不会有问题。
- 这样人只要一个方法就能逗任意种类的狗玩,哪怕是添加新的狗,人的类都不需要修改。
代码实现:
class Dog(object):def work(self): # 父类提供统一的方法,哪怕是空方法passclass ArmyDog(Dog): # 继承 Dogdef work(self): # 子类重写方法,并且处理自己的行为print('追击敌人')class DrugDog(Dog):def work(self):print('追查毒品')class Person(object):def work_with_dog(self, dog):dog.work() # 使用小狗可以根据对象的不同而产生不同的运行效果, 保障了代码的稳定性# 子类对象可以当作父类来使用
dog = Dog()
ad = ArmyDog()
dd = DrugDog()p = Person()
p.work_with_dog(dog)
p.work_with_dog(ad) # 同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性
p.work_with_dog(dd) # 并且传递不同对象,最终 work_with_dog 产生了不同的执行效果
- 最终效果
- Person 类中只需要调用 Dog 对象 work() 方法,而不关心具体是 什么狗
- work() 方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现
- 在程序执行时,传入不同的 Dog 对象作为实参,就会产生不同的执行效果
多态总结
- 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
- 好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!
- 实现步骤:
- 定义父类,并提供公共方法
- 定义子类,并重写父类方法
- 传递子类对象给调用者,可以看到不同子类执行效果不同
面向对象进阶 三大特性相关推荐
- Java学习笔记二十五:Java面向对象的三大特性之多态
Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...
- 面向对象的三大特性之继承
# 面向对象的三大特性之继承# 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好 (如机器人) # 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好 (动物-- ...
- 到底什么是面向对象,面试中怎么回答。面向过程和面向对象的区别是什么。java跨平台特性以及java和C++的区别。面向对象的三大特性——封装、继承和多态。面向对象的高拓展性以及低耦合度怎么体现?
Java语言具有的特点:面向对象.跨平台.多线程以及网络编程 1. 和C++的区别 1.1 Java隐蔽了C++的指针,避免指针直接操作,程序更加安全. 1.2 Java类继承只能单继承,避免了C++ ...
- 面向对象之三大特性:继承,封装,多态
python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分 ...
- Python Day 21 面向对象 (面向对象的三大特性(二)继承,多态,封装,几个装饰器函数)...
Python Day 21 面向对象 (面向对象的三大特性(二)继承,多态,封装,几个装饰器函数) https://mubu.com/doc/1AqL_M0IbW 继承之钻石继承 多态 封装 几个装饰 ...
- polymorphism java_Java基础-面向对象第三大特性之多态(polymorphism)
Java基础-面向对象第三大特性之多态(polymorphism) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多态概述 多态是继封装,继承之后,面向对象的第三大特性,多态的 ...
- C++ 面向对象程序三大特性之 继承
目录 继承的概念 继承的定义及使用 继承方式和访问权限 基类和派生类对象的赋值转换 继承中的各成员的作用域 派生类的默认成员函数 构造函数 拷贝构造 赋值运算符重载函数 析构函数 继承与友元 继承与静 ...
- 面向对象的三大特性:封装、继承、多态
面向对象的三大特性 面向对象的三大特性:封装.继承.多态 封装 封装,成员变量的封装,保证了数据的安全性.封装的好处:过滤了不合理的值.屏蔽内部的赋值过程.让外界不必关注内部的细节 Set方法 1. ...
- 面向对象:三大特性与五大原则
面向对象:三大特性与五大原则 面向对象(Object Oriented, OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构.应用平台.分布 ...
最新文章
- hdu4717 三分(散点的移动)
- 机器学习-k均值聚类算法-k_means原理14
- 万亩良田,随着稻香河流IoT奔跑
- redis在windows10上跑起来
- php ios支付宝不回调,支付宝 支付成功 ios 不回调
- 【轻量级网络】MobileNet-v2详解
- ajax datatype_jQuery中的 AJAX
- IOS开发之视图和视图控制器
- matlab2c使用c++实现matlab函数系列教程-mean函数
- vrep与vs2015联合仿真(C/C++)
- 使用Markdown编写手册
- 新巴塞尔资本协议(中英文)
- 根据经纬度查询位置百度api
- mysql添加表或字段注释
- Mac port 安装postgres92 + postgres92-server
- 1024程序员节,向改变世界的程序员致敬
- Pinia的简单使用
- (Python)爬虫学习(一)
- 视频话题识别与跟踪 - demo 【问题总结1.1-视频处理】
- CBNData:骑行大数据寻找城市热点之购物中心篇
热门文章
- 怎样设置一个函数C语言,C语言中怎样编写一个函数 如何在C语言中定义一个函数?...
- 基于华为巴龙MH5000-31 5G工业/商业模组开发(二)
- 100个精选Python实战项目案例,送给缺乏练手经验的你
- Linux修改fstab引起系统无法启动问题的解决方法
- 阿里面试题-判断是不是一个IP地址的测试用例设计(Python实现)
- 为什么要用VR全景?5个答案告诉你
- 学计算机是不是必须要买电脑,上大学了,你必须买一部电脑吗?
- OpenGL如何显示透明PNG
- 高德地图PC版国内首发室内地图
- 【web前端初级课程】第二章 CSS层叠样式表