面向对象设计(Object oriented design):将一类具体事物的数据和动作整合到一起,即面向对象设计
面向对象编程(object-oriented programming):用定义类+实例/对象的方式去实现面向对象的设计
1. 类和对象
1.什么叫类:类是一种数据结构,就好比一个模型,该模型用来表述一类事物(事物即数据和动作的结合体),用它来生产真实的物体(实例)。
2.什么叫对象:睁开眼,你看到的一切的事物都是一个个的对象,你可以把对象理解为一个具体的事物(事物即数据和动作的结合体)
(铅笔是对象,人是对象,房子是对象,狗是对象,alex是对象,配齐是对象,元昊是对象)
3.类与对象的关系:对象都是由类产生的,上帝造人,上帝首先有一个造人的模板,这个模板即人的类,然后上帝根据类的定义来生产一个个的人
4.什么叫实例化:由类生产对象的过程叫实例化,类实例化的结果就是一个对象,或者叫做一个实例(实例=对象)
类是用来描述一类事物,类的对象指的是这一类事物中的一个个体
是事物就要有属性,属性分为
1:数据属性:就是变量
2:函数属性:就是函数,在面向对象里通常称为方法
注意:类和对象均用点来访问自己的属性
类的函数属性还没有传参数
#注意:类和对象均用点来访问自己的属性 class Chinese: "这个一个中国人的类" dang = "***" #类的数据属性:就是变量 def sui_di_tu_tan(): #类的函数属性:就是函数,在面向对象里通常称为方法 print("吐了一口痰") def cha_dui(self): #函数属性:就是函数,在面向对象里通常称为方法 print("插到了前面") print(Chinese.dang) Chinese.sui_di_tu_tan() Chinese.cha_dui("先随便传一个参数") print("---------------") #类名.__dict__:查出的是一个字典,key为属性名,value为属性值 print(Chinese.__dict__["dang"]) # __dict__ 里面存的是Chinese 的属性字典 Chinese.__dict__["sui_di_tu_tan"]() # 可以通过 __dict__ 里面的key调用Chinese的属性 Chinese.__dict__["cha_dui"]("先随便传一个参数")
类和对象
#def __init__(self,name,age,gender): #实例化的过程可以简单理解为执行该函数的过程,实例本身会当作参数传递给self(这是默认的步骤)
class Chinese: "这个一个中国人的类" dang = "***" #类的数据属性:就是变量 def __init__(self,name,age,gender): #实例的数据属性 self.mingzi = name self.nl = age self.xb = gender def sui_di_tu_tan(self): #类的函数属性:就是函数,在面向对象里通常称为方法 print("%s %s %s 吐了一口痰"%(self.mingzi,self.nl,self.xb)) def cha_dui(self): #类的函数属性:就是函数,在面向对象里通常称为方法 print("%s 插到了前面"%self.mingzi) p1 = Chinese("tom",18,"男") #实例化 创建一个对象p1 print(p1.mingzi,p1.nl,p1.xb) #打印实例的数据属性 print(p1.__dict__) # __dict__ 里面存的是p1 的属性字典 print(p1.dang) #先在实例(对象)的__init__的数据属性里找,找不到就找类的数据属性 p1.sui_di_tu_tan() #类的函数属性,会自动把p1传给self p1.cha_dui() #类的函数属性,会自动把p1传给self
类的增删改查
class Chinese: councry = "china" def __init__(self,name): self.name = name def paly_ball(self,ball): print("%s 正在打 %s"%(self.name,ball)) #查看类的数据属性 print(Chinese.councry) #修改类的数据属性 Chinese.councry = "Japan" print(Chinese.councry) # 实例化 创建一个对象 p1 = Chinese("tom") print(p1.__dict__) #增加类的数据属性 Chinese.dang = "***" print(Chinese.dang) #删除类的数据属性 del Chinese.dang # 增加类的函数属性 def eat_foot(self,foot): print("%s 正在吃 %s"%(self.name,foot)) Chinese.eat = eat_foot # 增加类的函数属性 p1.eat("屎") # 对象调用类的函数属性 p1.paly_ball("篮球") # 修改类的函数属性 def test(self): print("test") Chinese.paly_ball = test #修改类的函数属性 p1.paly_ball()
对象的增删改查
class Chinese: councry = "china" def __init__(self,name): self.name = name def paly_ball(self,ball): print("%s 正在打 %s"%(self.name,ball)) p1 = Chinese("tom") #实例化 创建对象 print(p1.__dict__) #查看实例的数据属性 #查看实例的数据属性 print(p1.name) #增加实例的数据属性 p1.age = 18 print(p1.__dict__) #删除实例的数据属性 del p1.age print(p1.__dict__) #修改实例的数据属性 p1.name = "liaoboshi" print(p1.__dict__)
特殊的类属性
class ChinesePeople: '我们都是中国人,我们骄傲的活着,我们不服任何事和物' government='***' def sui_di_tu_tan(): print('90%的中国人都喜欢随地吐痰') def cha_dui(self): print('一个中国人-->%s<--插到了前面' %self) print(ChinesePeople.__name__)# 类C的名字(字符串) print(ChinesePeople.__doc__)# 类C的文档字符串 print(ChinesePeople.__base__)# 类C的第一个父类(在讲继承时会讲) print(ChinesePeople.__bases__)# 类C的所有父类构成的元组(在讲继承时会讲) print(ChinesePeople.__dict__)# 类C的属性 print(ChinesePeople.__module__)# 类C定义所在的模块 print(ChinesePeople.__class__)# 实例C对应的类(仅新式类中)
静态属性
class Room: def __init__(self,name,owner,le,wight,heigh): self.name = name self.owner = owner self.le = le self.wight = wight self.heigh = heigh @property # 静态属性 把函数属性伪装成数据属性 def cal_dz(self): return (self.le*self.wight*self.heigh)*0.5 r = Room("房间","tom",2,2,2) print(r.cal_dz)
静态方法
class Room: tag = 1 def __init__(self,name,owner): self.name = name self.owner = owner @staticmethod #静态方法 def wash_body(a,b,c): print("洗----->",a,b,c) Room.wash_body(1,2,3) #类可以使用 r = Room("房间","tom") r.wash_body(1,2,3) #实例也可以使用
类方法
class Room: tag = 1 def __init__(self,name,owner): self.name = name self.owner = owner @classmethod # 类方法 专门给类使用,与实例无关 类方法只能访问类相关的属性,不能访问实例属性(与实例无关) def tell_info(cls): print(cls) print("----->",cls.tag) Room.tell_info()
组合
class School: def __init__(self,name,addr): self.name = name self.addr = addr def zhao_sheng(self): print("%s %s 正在招生"%(self.addr,self.name)) class Course: def __init__(self,name,price,period,school): self.name = name self.price =price self.period = period self.school = school s1 = School("oldboy","北京校区") s2 = School("oldboy","深圳校区") s3 = School("oldboy","广州校区") c = Course("python",15800,"5M",s2) #把学校的实例传进去 print(c.__dict__) # 输出 实例c 的属性字典 c.school.zhao_sheng() # 执行 实例s2 的zhao_sheng 函数属性
继承
class Dad: money = 10 def __init__(self,name): print("------Dad------") self.name = name def hit_son(self): print("%s 正在打son"%self.name) class Son(Dad): money = 10000 s = Son("tom") # 实例Son的类,Son类中没有__init__方法,会调父类中的__init__方法,并且要传父类中要的参数 print(s.money) #===>10000 # 查看Son类的money属性 ,没有会找父类的 s.hit_son() #===>tom 正在打son # 调用Son类的hit_son方法,没有会找父类的 print(Dad.money) #===>10 # 子类和父类都有money的属性,子属的money属性不会覆盖父类的
接口继承
import abc class All_file(metaclass = abc.ABCMeta): @abc.abstractmethod #子类要实例化,必须定义用@abc.abstractmethod 修饰的方法 def read(self): pass @abc.abstractmethod def writ(self): pass class Disk(All_file): def read(self): print("disk read") def writ(self): print("disd writ") class Mem(All_file): def read(self): print("mem read") def writ(self): print("mem writ") m = Mem() #想要实例,Mem类必须定义父类用@abc.abstractmethod修饰的方法 m.read() m.writ()
继承顺序
class A: def test(self): print("A") class B(A): def test(self): print("B") # pass class C(A): def test(self): print("C") # pass class D(B): def test(self): print("D") # pass class E(C): def test(self): print("E") # pass class F(D,E): def test(self): print("F") # pass f = F() f.test() # 继承顺序有 深度优先和广度优先 print("F的继承顺序",F.__mro__) # python3 的继承顺序是广度优先
在子类中调用父类的属性和方法(super方法的使用)
class Vehicle: councry = "china" def __init__(self,name,speed,load,power): self.name = name self.speed = speed self.load = load self.power = power def run(self): print("开动了") print("开动了") print("开动了") class Subway(Vehicle): def __init__(self,name,speed,load,power,line): # Vehicle.__init__(self,name,speed,load,power) #调用父类的__init__方法,不用再初始化一次 super().__init__(name,speed,load,power) #调用父类的__init__方法,不用再初始化一次 self.line = line def test(self): print(self.name,self.speed,self.load,self.power,self.line) def run(self): # Vehicle.run(self) # 可以运行子类与父类相同的 run 方法 不会只运行子类的 run 方法 super().run() # 可以运行子类与父类相同的 run 方法 不会只运行子类的 run 方法 print(" %s 开动了"%self.name) s = Subway("北京地铁","100km/h",500,"电",13) #实例s s.test() #通过实例s调用Subway的方法 s.run() #通过实例s调用子类和父类的run方法
多态
#类的继承有两层意义:1.改变 2.扩展 #多态就是类的这两层意义的一个具体的实现机制 #即,调用不同的类实例化得对象下的相同的方法,实现的过程不一样 #python中的标准类型就是多态概念的一个很好的示范 class H2o: def __init__(self,name,wd): self.name = name self.wd = wd def turn_ice(self): if self.wd < 0 : print("%s 温度小于0变冰了"%self.name) elif self.wd >0 and self.wd <100: print("%s 液化成水了"%self.name) elif self.wd >100 : print("%s 温度太高变水蒸气了"%self.name) class S(H2o): pass class Ice(H2o): pass class Szq(H2o): pass s = S("水",20) i = Ice("冰",-20) sz = Szq("水蒸气",120) def func(obj): obj.turn_ice() func(s) func(i) func(sz)
封装
class People: star = "地球" def __init__(self,id,name,age): self.name = name self.id = id self.age = age p = People("231243","tom",18) print(p.star) class People: _star = "地球11111" def __init__(self,id,name,age): self.name = name self.id = id self.age = age p = People("231243","tom",18) print(p._star) # _属性名 的属性不建议在外面使用 class People: __star = "地球222222" # __属性名 python 用自动重命名为 _类名__属性名 __属性名 的属性不建议在外面使用 def __init__(self,id,name,age): self.name = name self.id = id self.age = age p = People("231243","tom",18) print(People.__dict__) print(p._People__star) # __属性名 python 用自动重命名为 _类名__属性名,如果通过 __属性名 会报错
包装标准类型
class List(list): def append(self, p_object): #修改类List(list父类基础上)的append方法 if type(p_object) is str: #只能添加字符串 super().append(p_object) else: print("只能加字符串") # def min(self): # 在列表类的基础上加了一个可以查到列表中间元素的方法 # i = int(len(self)/2) # return self[i] l = List("helloworld") print(l) # print(l.min()) #查看中间元素 l.append("tom") print(l)
反射
class Heizj(): def __init__(self,name,addr): self.name = name self.addr = addr def sell_house(self): print("%s 正在卖房子"%self.name) h = Heizj("万盛置地","天露园") print(hasattr(h,"name")) #检测对象是否有这个属性 #获取对象属性 print(getattr(h,"name")) #获取对象属性 a = getattr(h,"sell_house") a() # # print(getattr(h,"fjdiohg")) #获取对象属性,没有这个属性就报错 print(getattr(h,"fjdiohg","123")) #获取对象属性,没有这个属性不报错,会输出第三个参数 setattr(h,"sb","tom") #设置属性,没有这个属性就添加到属性字典里 setattr(h,"name","456") #设置属性,有这个属性,就修改这个属性 print(h.__dict__) #查看属性 delattr(h,"sb") #删除属性 # delattr(h,"fas") #删除属性,没有就报错 print(h.__dict__) #查看属性
双下划线attr方法系列
class Foo: x = 1 def __init__(self,y): self.y = y def __getattr__(self, item): print("__getattr__运行了") f = Foo(10) print(f.x) f.sssssssss #运行的属性 当类里没有的时候 就自动会运行__getattr__方法 class Foo: x = 1 def __init__(self,y): self.y = y def __delattr__(self, item): print("__delattr__运行了") f = Foo(10) del f.x #一有删除操作就会运行__delattr__方法 del f.y class Foo: x = 1 def __init__(self,y): self.y = y def __setattr__(self, key, value): print("__setattr__运行了") # self.key = value self.__dict__["key"] = value #设置属性的时候会自动调用__setattr__, 上一行会无限递归,直接设置__dict__不会 f = Foo(10) print(f.__dict__) f.z = 5 print(f.__dict__)
双下划线item方法系列
# 触发双下划线item系列,要调用 f1["name"] ,就是要通过中括号去调用才会触发 # 触发双下划线attr系列,要调用 f1.name ,就是要 点 去调用用才会触发 class Foo(): def __getitem__(self, item): print("__getitem__") return self.__dict__[item] def __setitem__(self, key, value): print("__setitem__") self.__dict__[key] = value def __delitem__(self, key): print("__delitem__") self.__dict__.pop(key) f1 = Foo() print(f1.__dict__) #f1.name = "tom" #__setitem__ f1["name"] = "tom" f1["age"] = 18 print("=====>",f1.__dict__) #__delitem__ del f1["name"] print(f1.__dict__) #__getitem__ print(f1["age"])
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): self.file=open(filename,mode,encoding=encoding) def write(self,line): t=time.strftime('%Y-%m-%d %T') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): return getattr(self.file,item) f1=FileHandle('b.txt','w+') f1.write('你好啊') f1.seek(0) print(f1.read()) f1.close() #授权示范一
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' #我们来加上b模式支持 import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): if 'b' in mode: self.file=open(filename,mode) else: self.file=open(filename,mode,encoding=encoding) self.encoding=encoding def write(self,line): t=time.strftime('%Y-%m-%d %T') if 'b' in self.mode: msg=bytes('%s %s' %(t,line),encoding=self.encoding) self.file.write(msg) def __getattr__(self, item): return getattr(self.file,item) f1=FileHandle('b.txt','wb') f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气 f1.close() #授权示范二
__format__用法
#自定义format练习 date_dic={ 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}/{0.month}/{0.year}', 'mdy':'{0.month}-{0.day}-{0.year}', } class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __format__(self, format_spec): if not format_spec or format_spec not in date_dic: format_spec='ymd' fmt=date_dic[format_spec] return fmt.format(self) d1=Date(2016,12,29) print(format(d1)) print(format(d1,"dmy")) print(format(d1,"mdy"))
__slots__方法
#少用 class Foo: __slots__ = ["name","age"] f1 = Foo() print(Foo.__dict__) f1.name = "tom" f1.age = 18 # f1.gender = "man" #不能设置__slots__里没有的属性 print(f1.name) print(f1.age) # print(f1.__dict__) #设置了__slots__,实例的对象没有__dict__的属性字典
__del__方法 析构方法
class Foo: def __del__(self): print("我执行了") f1 = Foo() del f1 #对象被删除时会调用__del__方法 print("-------------->") #程序运行完时也会调用__del__方法,因为程序运行完,Python解释器会回收对象。
__call__方法
# __module__ 表示当前操作的对象在那个模块 # __class__ 表示当前操作的对象的类是什么 class Foo: def __call__(self, *args, **kwargs): print("执行了---") f1 = Foo() f1() # f1的类Foo 下的__call__方法. 如果上面没有定义__call__方法,调用f1()用报错 Foo() # Foo的类 XXX 下的__call__方法
一 isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo(object): pass obj = Foo() isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)