admin管理员组文章数量:1573362
Python面向对象编程
参考教程:https://www.bilibili/video/av8475172?p=1
面向过程与面向对象
- 面向过程:自顶向下,用于解决计算问题或实现某种算法,与我们的思考方式一致,拿到问题,思考问题, 设计步骤,得出结果。通过函数/过程操纵表现世界的数据与状态,运行效率较高。
- 面向对象:自底向上,把世界描绘成具有主动性的对象之间的交互,运行效率较低。
体会区别
例子:在一维地图上,有一只虫子和一只蚂蚁,每一次他们都走过一个-3,-2,2,+3,三个随机单位的距离,达到边界放弃移动,处于同一位置时,蚂蚁吃掉虫子,游戏结束。
- 面向过程
import random
ant_point = random.randint(0,20)
worm_point = random.randint(0,20)
print("蚂蚁的位置:",ant_point,",虫子的位置:",worm_point)
step = [-3,-2,2,-3]
while ant_point != worm_point:
go_step = random.choice(step)
if 0 < ant_point+go_step < 20:
ant_point += go_step
go_step = random.choice(step)
if 0 < worm_point+go_step < 20:
worm_point += go_step
print("蚂蚁的位置:",ant_point,",虫子的位置:",worm_point)
- 面向对象
import random
class Sprite:
"""定义一个精灵类,是蚂蚁类和虫子类的父类,具有蚂蚁和虫子的一些共同特征"""
step = [-3,-2,2,3]
def __init__(self, gm, point=None):
self.gm = gm
if point is None:
self.point = random.randint(0,20)
else:
self.point = point
def jump(self):
go_step = random.choice(Sprite.step)
if 0 < self.point+go_step < 20:
self.point += go_step
class Ant(Sprite):
"""定义一个蚂蚁类,继承Sprite类"""
def __init__(self,gm,point=None):
super().__init__(gm,point)
self.gm.set_point("ant",self.point)
def jump(self):
super().jump()
self.gm.set_point("ant",self.point)
class Worm(Sprite):
"""定义一个虫子类,继承Sprite类"""
def __init__(self,gm,point=None):
super().__init__(gm,point)
self.gm.set_point("worm",self.point)
def jump(self):
super().jump()
self.gm.set_point("worm",self.point)
class GameMap:
def __init__(self):
# 初始化,设置最初位置为None
self.ant_point = None
self.worm_point = None
def catch(self):
# 判断是否相遇
print("蚂蚁的位置:",self.ant_point,";虫子的位置:",self.worm_point)
if self.ant_point is not None and self.worm_point is not None and self.worm_point == self.ant_point:
return True
def set_point(self,src,point):
if src == "worm":
self.worm_point = point
if src == "ant":
self.ant_point = point
if __name__ == '__main__':
gm = GameMap() # 创建一个游戏地图对象
worm = Worm(gm)
ant = Ant(gm)
while not gm.catch():
worm.jump()
ant.jump()
理解对象
- 对象可以指自然界中的任何事物
- 自然界中的事物的模型化
- 对象具有自身的属性和方法
- 对象通过实例化类产生
对象优越性
-
封装:将模型的特征和能力打包在一起,隐藏细节,外界只能对其进行调用,不能修改
-
继承:符合自然界的分类规律,快速的代码重用
-
多态:子类可以继承父类的特征和能力,还可以通过自定义来修改其特征和能力【鸭子类型】
-
组合:一个模型可以其他的模型组成
定义和使用类
1、定义方法
class 类名:
pass
2、使用方法
# 对象 = 类名()
tc = testClass()
3、类与实例之间的关系
定义类就是建立模型,实例化类就是创建一个实例,类是一个抽象的概念,代表具有同一特征和能力的某一类事物,实例是这类事物的具体体现。
4、实例属性
5、类属性
- 类属性在类定义后就存在,不需要实例化
- 类属性使得相同类的不同实例具有相同的属性
class Tree:
hight = 120
这样定义后所有实例化产生的的树hight都是120
6、私有属性
私有属性是在类的内部使用的属性,不能在外部对其进行修改
7、特殊属性
可以通过dir(类名)进行查看
特殊属性名 | 作用 |
---|---|
_doc_ | 查看文档 |
_name_ | 查看类名 |
_dict_ | 保存实例属性及键值 |
_module_ | 保存类所在的模块名 |
_base_ | 查看父类 |
类的方法
1、定义方法
def 方法名(self,...):
pass
其中self代表类的实例本身,在调用方法时由系统自动提供,方法定义时必须指明self参数。
2、类方法的使用
- 在类的内部调用:self.<方法名>.(参数列表)
- 在类分外部调用:实例名.<方法名>.(参数列表)
注:以上两种调用方法中,提供的参数列表中都不用包括self
3、构造方法及其作用
深入类的属性
1、类属性和实例属性重名
- 以实例名.属性名引用时,优先引用实例属性
- 以类名.属性名引用时,只能引用类属性
2、属性访问的特殊方法(反射)
-
提供用字符串来操作类的属性和方法
-
主要工具函数:
hasattr(obj_name,'属性名') # 测试实例是否具有某个属性 setattr(obj_name,'属性名',值) # 修改obj_name中的属性值 getattr(obj_name,'属性名') # 获取obj_name中的属性值
3、属性包装(装饰器)
将方法包装成属性,以隐藏相关实现
控制属性的类型或范围
虚拟属性(有其他属性处理后得来)
三种属性操作:
- 可读:@property
- 可写:@property-name.setter
- 可删:@property-name.deleter
4、描述符
-
将实现特殊协议的方法的类作为另一个类的类属性
-
用来拦截和控制属性访问并可以重复使用
-
协议方法
- _get_()
- _set_()
- _delete_()
-
分类:
- 数据描述符:实现全部协议方法
- 非数据描述符:实现部分协议方法
- 所有的类成员函数都是非数据描述符
-
同名的实例属性和非数据描述符(以方法为例)访问优先级:属性高于方法
-
注意:只能在新式类中使用
class NonNeg: def __init__(self,default=0): self.default = default def __get__(self, instance, owner): return self.default def __set__(self, instance, value): if value > 0: self.default = value else: print("不能为负值") def __delete__(self, instance): pass class Movie: rating = NonNeg() score = NonNeg() if __name__ == '__main__': m = Movie() print('rating:',m.rating) print('score:',m.score) m.rating = 80 print('rating:', m.rating) m.score = -3 print('score:', m.score)
5、__call__方法
使实例可以当作函数直接使用
class Tst:
def __call__(self, *args, **kwargs):
print("call")
t = Tst()
t()
类方法和静态方法
1、静态方法
2、类方法
类的继承与方法重载
1、继承
-
特点:
【1】减少代码和灵活定制新类
【2】子类具有父类的属性和方法
【3】子类不能继承父类的私有属性和方法
【4】子类可添加新的方法
【5】子类可以修改父类的方法
-
语法
# class 类名(继承的父类名): class Myclass(Baseclass): pass # class 类名(父类1,父类2,....) class Myclass(Baseclass1,Baseclass2): pass
2、重载
-
语法:直接定义和父类同名的方法
-
修改父类的方法
【1】在重载的方法中调用父类方法
# super().父类中的方法名 super().start_washer()
【2】同时添加相应的业务逻辑
【3】多重继承时如何调用父类方法:按括号内顺序进行调用
>>> class A: def foo(self): print('A foo') >>> class B: def foo(self): print('B foo') >>> class C(A,B): pass >>> c = C() >>> c.foo() A foo >>> class D(B,A): pass >>> d = D() >>> d.foo() B foo
类的特殊方法
1、深入理解类
2、元类
类的创建和管理者(type),所有的类都是元类(type)的实例
-
类实例化过程
先调用_new_(),
然后调用 _init_()
-
自定义元类
- 目的:对其创建的类进行预处理
- 继承type
- 定义__new()__方法
- 还可以定义__init()__方法
"""为每一个类创建info()方法和company属性""" class MyMeta(type): def __init__(self,name,bases,dicts): print("Init Instance.") def __new__(cls,name,bases,dicts): dicts['info'] = lambda self:print('Djx.') res = type.__new__(cls,name,bases,dicts) res.company = "Meizi" return res class custom(metaclass=MyMeta): pass if __name__ == '__main__': cus = custom() cus.info() print(cus.company)
-
应用元类
3、构造序列 ——使类成为序列
class MySeq:
def __init__(self):
self.lseq = ['I','II','III','IV']
def __len__(self):
return len(self.lseq)
def __getitem__(self, key):
if 0 <= key < 4:
return self.lseq[key]
if __name__ == '__main__':
m = MySeq()
for i in range(4):
print(m[i])
4、构造iter
class MyIter:
def __init__(self,start,end):
self.count = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.count < self.end:
r = self.count
self.count += 1
return r
else:
raise StopIteration
if __name__ == '__main__':
for i in MyIter(1,10):
print(i)
5、可比较类
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __lt__(self, other): # 小于的比较
return self.x < other.x
def __gt__(self, other): # 大于的比较
return self.y > other.y
if __name__ == '__main__':
pa = Point(0,1)
pb = Point(1,0)
print(pa < pb)
print(pa > pb)
6、构造可运算类
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x,self.y + other.y)
def info(self):
print(self.x,self.y)
if __name__ == '__main__':
pa = Point(1,2)
pb = Point(3,4)
pc = pa + pb
pc.info()
鸭子类型与多态
1、什么是多态
一种类型具有多种类型的能力,允许不同的对象对同一消息做出灵活的反应,以一种通用的方式对待可使用的对象,非动态语言必须通过继承和接口来实现
2、Python中的多态
通过继承实现多态(子类可以作为父类使用),子类通过重载父类的方法实现多态。
>>> class Animal: # 父类
def move(self):
print('Animal is moving...')
>>> class Dog(Animal): # 子类,继承Animal类
pass
>>> def move(obj):
obj.move()
>>> a = Animal()
>>> move(a)
Animal is moving...
>>> d = Dog()
>>> move(d)
Animal is moving...
>>> class Cat(Animal):
def move(self): # 重载
print('Cat is moving...')
>>> class Sheep(Animal):
def move(self): # 重载
print('Sheep is moving...')
>>> move(Sheep())
Sheep is moving...
>>> move(Cat())
Cat is moving...
3、动态语言与鸭子类型
4、多态的好处
- 可实现开放的扩展与修改的封闭
- 使python更具灵活性
Python与设计模式
1、设计模式
class SingleClass:
def __init__(self,x=0):
self.x = 0
sc = SingleClass()
def tsc():
print(sc.x)
sc.x = 10
print(sc.x)
def tsc2():
print(sc.x)
sc.x = 9
print(sc.x)
if __name__ == '__main__':
tsc()
tsc2()
class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_sgl'):
cls._sgl = super().__new__(cls,*args,**kwargs)
return cls._sgl
if __name__ == '__main__':
sa = Singleton()
sb = Singleton()
print(id(sa))
print(id(sb))
2、普通工厂模式
class Ab:
a = 3
class Ac:
a = 0
class MyFactory:
def get_instance(self,ins):
return ins()
if __name__ == '__main__':
mf = MyFactory()
print(type(mf.get_instance(Ab)))
print(type(mf.get_instance(Ac)))
# 结果
# <class '__main__.Ab'>
# <class '__main__.Ac'>
3、策略模式
class Moveable:
def move(self):
print('moving...')
class MoveOnFeet(Moveable):
def move(self):
print("move on feet")
class MoveOnWheel(Moveable):
def move(self):
print("move on wheel")
class MoveObj:
def set_move(self,moveable):
self.moveable = moveable()
def move(self):
self.moveable.move()
if __name__ == '__main__':
m = MoveObj()
m.set_move(Moveable)
m.move()
m.set_move(MoveOnFeet)
m.move()
m.set_move(MoveOnWheel)
m.move()
def movea():
print("move a")
def moveb():
print("move b")
class MoveObj:
def set_move(self,moveable):
self.moveable = moveable
def move(self):
self.moveable()
if __name__ == '__main__':
m = MoveObj()
m.set_move(movea)
m.move()
m.set_move(moveb)
m.move()
# 结果
# move a
# move b
4、装饰模式
1、原理
# 例1
class BeDeco:
def be_edit_fun(self):
print('Source fun.')
def be_keep_fun(self):
print('keep fun.')
class Decorater:
def __init__(self,dec):
self._dec = dec()
def be_edit_fun(self):
print('Start...')
self._dec.be_edit_fun()
def be_keep_fun(self):
self._dec.be_keep_fun()
if __name__ == '__main__':
bd = BeDeco()
bd.be_edit_fun()
bd.be_keep_fun()
dr = Decorater(BeDeco)
dr.be_edit_fun()
dr.be_keep_fun()
# 结果
Source fun.
keep fun.
Start...
Source fun.
keep fun.
# 例2
class Water:
def __init__(self):
self.name = 'Water'
def show(self):
print(self.name)
class Deco:
def show(self):
print(self.name)
class Salt(Deco):
def __init__(self,water):
self.name = 'Salt'
self.water = water
def show(self):
print(self.name)
print(self.water.name)
class Suger(Deco):
def __init__(self,water):
self.name = 'Suger'
self.water = water
def show(self):
print(self.name)
print(self.water.name)
if __name__ == '__main__':
w = Water()
s = Suger(w)
s.show()
s = Salt(w)
s.show()
# 结果
Suger
Water
Salt
Water
2、类装饰器
def deco(a_class):
class newClass:
def __init__(self,age,color):
self.age = age
self.color = color
def display(self):
print(self.age)
print(self.color)
return newClass # 必须返回新类
@deco # 装饰器标志
"""
去掉后报错
c = Cat(12,'black')
TypeError: __init__() takes 2 positional arguments but 3 were given
"""
class Cat:
def __init__(self,age):
self.age = age
def display(self):
print(self.age)
if __name__ == '__main__':
c = Cat(12,'black')
c.display()
# 结果
12
black
通过组合来构建复杂的对象
1、理解组合
- 类似用各种零件组装机器
- 零件-----基础类;机器-------包含其他类的类
- 体现自下而上的面向对象编程方法
2、组合案例——雪人
-
面向对象分析 ——雪人分为哪几部分
-
抽象出基类
- Shape:不同角度参数的图形元素
- ShapeAngles:需要角度参数的图形元素
-
实现基类
class Shape: def __init__(self,cvns,points): # cvns--画布;points--位置 self.cvns = cvns self.points = points self.pid = None def delete(self): # 删除图像 if self.pid: self.cvns.delete(self.pid) class ShapeAngle(Shape): def __init__(self,cvns,points,angles=(10,170)): super().__init__(cvns,points) self.angles = {'start':angles[0],'extent':angles[1]}
-
实现子类
- HatTop —— 帽子顶部
- HatBottom ——帽子底端
- Face ——脸
- Sense —— 五官
- BodyOutline —— 身体轮廓
- Button —— 纽扣
面向对象开发实例——图形化时钟程序
1、项目描述
运用python的tkinter库开发图形化时钟程序:
- 时钟启动时以系统时间为当前时间
- 时钟有时针、分针和秒针
- 表盘可以切换为程序绘制的或基于图片的
2、钟表——对象分析
3、对象属性
- 指针
-
基本表盘
-
图像表盘
- 钟表
- 三种类型的指针
- 表盘
- 切换表盘
- 按钮——切换表盘
4、源码
由于对tkinter库没有深入了解,对一些内部实现未能掌握,表盘背景的更改未能实现,此源码主要为了体验面向对象编程
import time,datetime
import math
import itertools
import tkinter
import threading
def get_clock_step(base_pntr,long_pntr):
# 获取指针坐标点
pos = []
for i in range(60):
pos.append((base_pntr[0]+long_pntr*math.cos(i*math.pi/30),base_pntr[0]+long_pntr*math.sin(i*math.pi/30)))
return pos[45:] + pos[:45]
def gen_i_pos(c_pntr,long_pntr):
# 将坐标点包装成一个生成器
for i,p in enumerate(get_clock_step(c_pntr,long_pntr)):
yield i,p
class Pointer:
def __init__(self,c_pntr,long_pntr,cvns,scale=None,super_pntr=None,width=1,fill='black'):
# 参数说明:
# c_pntr:表盘的中心坐标
# long_pntr:表针长
# cvns:画布引用
# scale:指针行走比例
# super_pntr:上级指针
# width:指针粗细
# fill:指针颜色
self.pos_iter = itertools.cycle(gen_i_pos(c_pntr,long_pntr))
self.scale = scale
self.cvns = cvns
self.crrnt_pos = self.pos_iter.__next__()[1]
self.c_pntr = c_pntr
self.super_pntr = super_pntr
self.id_pntr = None
self.width = width
self.fill = fill
def draw(self):
self.id_pntr = self.cvns.create_line(self.c_pntr,self.crrnt_pos,width=self.width,fill=self.fill)
def delete(self):
if self.id_pntr:
self.cvns.delete(self.id_pntr)
def walk_step(self):
self.delete() # 删除上一时刻的指针
self.draw() # 创建当前时刻的指针
i,self.crrnt_pos = self.pos_iter.__next__()
if self.super_pntr and self.scale and (i+1)%self.scale == 0:
# 判断上级指针是否需要行走
self.super_pntr.walk_step()
def set_start(self,steps):
for i in range(steps - 1):
self.pos_iter.__next__()
self.crrnt_pos = self.pos_iter.__next__()[1]
class PlateImg:
def __init__(self,c_pntr,clock_r,cvns,img):
self.cvns = cvns
self.clock_r = clock_r
self.c_pntr = c_pntr
self.img = img
self.pid = None
self.draw()
def draw(self):
self.im = tkinter.PhotoImage(file=self.img)
self.pid = self.cvns.create_line(self.c_pntr,image=self.im)
def delete(self):
if self.pid:
self.cvns.delete(self.pid)
def set_img(self,img):
self.img = img
self.delete()
self.draw()
class InImg(PlateImg):
def draw(self):
x = self.c_pntr[0]
y = self.c_pntr[0] + self.clock_r/5
self.im = tkinter.PhotoImage(file=self.img)
self.pid = self.cvns.create_line(x,y,image=self.im)
class CustomPlate:
def __init__(self,c_pntr,clock_r,cvns,imgp='patex.gif',imgi='flowersx.gif'):
self.pi = PlateImg(c_pntr,clock_r,cvns,imgp)
self.ii = InImg(c_pntr,clock_r,cvns,imgi)
def set_img(self,imgp,imgi):
self.pi.set_img(imgp)
self.ii.set_img(imgi)
def delete(self):
self.pi.delete()
self.ii.delete()
class Plate:
def __init__(self,c_pntr,clock_r,cvns,long=10):
self.pos_a = get_clock_step(c_pntr,clock_r-long)
self.pos_b = get_clock_step(c_pntr,clock_r)
self.cvns = cvns
self.plates = []
self.draw()
def draw(self):
for i,p in enumerate(zip(self.pos_a,self.pos_b)):
width = 5 if (i+1)%5 == 0 else 3
pid = self.cvns.create_line(*p,width=width)
self.plates.append(pid)
def delete(self):
if self.plates:
for item in self.plates:
self.cvns.delete(item)
class MyClock:
def __init__(self,base_pntr,clock_r,cvns):
self.c_pntr = base_pntr
self.clock_r = clock_r
self.cvns = cvns
self.plate = Plate(base_pntr,clock_r,self.cvns)
h,m,s = self.start_time()
self.h_pntr = Pointer(base_pntr, 3 * clock_r // 5,self.cvns,width=5,fill='blue')
self.m_pntr = Pointer(base_pntr,4 * clock_r // 5,self.cvns,12,super_pntr=self.h_pntr)
self.h_pntr.set_start(h * 5)
self.m_pntr.set_start(m)
self.h_pntr.walk_step()
self.m_pntr.walk_step()
self.s_pntr = Pointer(base_pntr,clock_r-5,self.cvns,60,super_pntr=self.m_pntr,fill='red')
self.s_pntr.set_start(s)
def chg_plate(self):
self.plate.delete()
if isinstance(self.plate,CustomPlate):
self.plate = Plate(self.c_pntr,self.clock_r,self.cvns)
else:
self.plate = CustomPlate(self.c_pntr,self.clock_r,self.cvns)
self.h_pntr.delete()
self.h_pntr.draw()
self.m_pntr.delete()
self.m_pntr.draw()
def set_img(self,imgp,imgi):
if not isinstance(self.plate,CustomPlate):
self.chg_plate()
self.plate.set_img(imgp,imgi)
def walk_step(self):
self.s_pntr.walk_step()
def start_time(self):
crrnt_time = datetime.datetime.now()
hour = crrnt_time.hour
minute = crrnt_time.minute
second = crrnt_time.second
return hour,minute,second
class MyButton:
def __init__(self,root,clock):
self.clock = clock
button = tkinter.Button(root,text="改变表盘",command=self.chg_plate)
button.pack()
def chg_plate(self):
self.clock.chg_plate()
class MyTk(tkinter.Tk):
def quit(self):
# tkinter.Tk.StartClock.looping = False
StartClock.looping = False
self.quit()
class StartClock:
looping = True
def __init__(self,mc,root):
self.mc = mc
self.root = root
def start_clock(self):
while StartClock.looping:
self.mc.walk_step()
self.root.update()
time.sleep(0.05)
if __name__ == '__main__':
root = MyTk()
cvns = tkinter.Canvas(root,width=400,height=400,bg='white')
cvns.pack()
mc = MyClock((200,200),200,cvns)
bt = MyButton(root,mc)
t = threading.Thread(target=StartClock(mc,root).start_clock)
t.setDaemon(True)
t.start()
root.resizable(False,False)
root.mainloop()
版权声明:本文标题:Python面向对象编程随笔 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1727746335a1127847.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论