面向对象(三)&模块
多态
- 多态是面向对象的三大特性之一。从字面理解就是多种形态
- 一个对象可以以不同形态去呈现
- 面向对象三大特性
• 封装 确保对象中数据的安全
• 继承 保证了对象的扩展性
• 多态 保证了程序的灵活性
class A(object):
def __init__(self,name):
self.name = name
def run(self):
print('%S会跑' % self.name)
class B(object):
def __init__(self,name):
self.name = name
def run(self):
print('%S会跑' % self.name)
a = A('猫')
b = B('狗')
def fun1(res):
res.run()
fun1(a) # 得 猫会跑
fun1(b) # 得 狗会跑
# 传递给函数 fun1(res) 的参数 res 可以是任何数据类型的实例,只要它有一个 run() 的方法即可。
# 其他类具备 run() 方法也可以使用 fun1 函数。这就是动态语言,动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。
- Python中多态的特点
• 1、只关心对象的实例方法是否同名,不关心对象所属的类型;
• 2、对象所属的类之间,继承关系可有可无;
• 3、多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;
• 4、多态是调用方法的技巧,不会影响到类的内部设计。 - 鸭子类型 :如果一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么它就是鸭子。
可以在其他用到“鸭子”的地方,用“这只鸟”替换。这就好比多态
属性和方法
- 属性
• 类属性,直接在类中定义的属性是类属性
• 类属性可以通过类或类的实例访问到。但是类属性只能通过类对象(cls)来修改,无法通过实例对象(self)修改
• 实例属性 通过实例对象添加的属性属于实例属性
• 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
calss Circle(object):
__pi = 3.14 # 私有化类方法
def __init__(self,r):
self.r = r
cricle1 = Circle(1)
Circle.pi = 3.141 # 通过类对象修改类属性
print(Circle.pi)
circle1.pi = 3.1415 # 通过实例对象修改实例属性
print(Circle.pi,circle1.pi)
- 方法
• 在类中定义,以self为第一个参数的方法都是实例方法
• 实例方法在调用时,Python会将调用对象以self传入
• 实例方法可以通过类实例和类去调用
• 当通过实例调用时,会自动将当前调用对象作为self传入
• 当通过类调用时,不会自动传递self,我们必须手动传递self
• 类方法 在类的内容以@classmethod 来修饰的方法是类方法
• 类方法第一个参数是cls 也会自动被传递。cls就是当前的类对象
• 类方法和实例方法的区别,实例方法的第一个参数是self,类方法的第一个参数是cls
• 类方法可以通过类去调用,也可以通过实例调用
class Circle(object):
__pi = 3.14
def __init__(self, r):
self.r = r
'''
@classmethod 装饰的方法不能使用实例属性,只能是类属性。
它主要使用在和类进行交互,但不和其实例进行交互的函数方法上。
'''
@classmethod
def pi(cls): # 类方法
return cls.__pi
def area(self): # 实例方法
return self.r ** 2 * self.__pi
print(Circle.pi()) # 没有实例化 能直接访问pi() 方法
circle1 = Circle(2)
print(circle1.pi()) # 也可以通过实例访问pi()方法
Circle类下的pi()方法被 @classmethod 装饰后,我们能通过Circle.pi() 直接运行方法,不用实例化类。
- 静态方法
• 在类中用@staticmethod来修饰的方法属于静态方法
• 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例调用
• 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
• 静态方法一般都是些工具方法,和当前类无关
class A(object):
def __init__(self, name):
self.name = name
def action(self):
print('%s在唱歌' % self.name)
@staticmethod
def wen(): # 不强制传递参数
pass
a = A('小红')
a.action()
print(A.wen,a.wen) # 得到 两个id相同
- 总结:一句话@staticmethod 修饰的方法是放在类外的函数,我们为了方便将他移动到了类里面,它对类的运行无影响。
单例模式
- 单例模式介绍
单例模式是一种常用的软件设计模式。也就是说该类只包含一个实例。 - 通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
- 通常应用在一些资源管理器中,比如日志记录等。
- _new_()方法:用于创建与返回一个对象(self)。在类准备将自身实例化时调用。
class Demo(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
print("__new__")
d = Demo() # 得 __new__
# 对象创建执行顺序,通过__new__()方法创建对象,并将对象返回,传给__init__()
注意
- _new_()方法用于创建对象
- _init_()方法在对象创建的时候,自动调用
- 但是此处重写了父类的_new_()方法,覆盖了父类_new_()创建对象的功能,所以对象并没有创建成功。所以仅执行_new_()方法内部代码
- 单例模式实现
思路
• 当对象不存在时,创建对象
• 当对象存在时,永远返回当前已经创建对象
class single(object):
__isinstance = None
def __new__(cls, *args, **kwargs):
if cls.__isinstance is None:
cls.__isinstance = super().__new__(cls)
return cls.__isinstance
else:
return cls.__isinstance
a = single()
b = single()
print(id(a))
print(id(b)) # 得 两个id相同
模块的创建
-
代码越来越多的时候,我们将代码写到一个.py 文件里,随着代码的增加,代码的维护越来越困难。如果将代码按照不同的功能拆分放到不同的.py文件中,每个.py文件就是一个模块。
-
不同模块中的变量名可以相同,他们不会受影响。
-
在创建许许多多模块后,我们可能希望将某些功能相近的文件组织在同一文件夹下,这里就需要运用包的概念了。
-
包是带有__init__.py文件的文件夹。包必须有__init__.py文件,不然他就是个文件夹。
-
包是用来区分不同类型的模块,不同包中的模块名可以相同,他们不会相互受影响。当然包下可以还有包(子包),如同子文件夹。
com/ # 顶层包
__init__.py # 初始化 com包
requirements.txt # requirements 文件
comtest.py # com 下comtest模块
woodman/ # com下的子包
__init__.py
woodtest.py
...
gif/ # 图片处理包
__init__.py
gifecho.py # gif 下gifecho模块
giftest.py # 注意添加代码
...
modle/ # modle子包
__init__.py
model.py # modle 下model模块
将代码添加到 giftest.py 中
gif = '1.gif'
def add(a, b):
print('add', a + b)
class giftest(object):
def minus(self, a, b):
print('giftest.minus', a - b)
1. 模块
- 模块化指将一个完整的程序分解成一个个的小模块
- 通过将模块组合,来搭建出一个完整的程序
- 模块化的有点
• 方便开发
• 方便维护
• 模块可以复用 - 2. 模块的创建
• 在Python当中一个py文件就是一个模块
• 在一个模块中引入外部模块 import 模块名(模块名就是py文件)
• 可以引入同一个模块多次,但是模块的实例只会创建一次
• import 模块名 as 模块别名
• 在一个模块内部都有一个_name_。通过它我们可以获取模块的名字
• 如果py文件直接运行时,那么__name__默认等于字符串’_main_’。__name__属性值为__main__的模块是主模块。一个程序中只有一个主模块
import pygame # 导入第三方模块
import test1 # 导入本地模块
import pygame as game # 给模块取别名
from pygame import 变量 # 从模块中导入变量\函数\类名
当文件在当前目录下或PATH环境变量下,可以直接 【import 文件名】引入 ;否则要从项目根目录下开始指定路径。
别名,直接引入文件名可以不用别名,如果带模块路径引入最好加上别名,使用时通过 【别名. 】使用
练习
在自定义类中实现创建对象
# 思路
#重写父类__new__()方法
#并且在该方法内部,调用父类的__new__()方法
class Demo(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
print("__new__")
return super().__new__(cls)
d = Demo() # 得 __new__ __init__
注意
- 在创建对象时,一定要将对象返回,在会自动触发__init__()方法
- init()方法当中的self,实际上就是__new__返回的实例,也就是该对象
- _init_()与_new_()区别
__init__实例方法,__new__静态方法
__init__在对象创建后自动调用,__new__创建对象的方法
声明:本文为学习笔记,转载请标明出处,本文仅供交流学习,请勿用于非法途径,希望本文对大家有帮助。
仅是个人意见,如有不足之处或者侵权,请留言!