面向对象(object-oriented ;简称: OO) 至今尚未统一的概念 我这里把它定义为: 按人们 认识客观世界的系统思惟方式,采用基于对象(实体) 的概念创建模型,模拟客观世界分析、设 计、实现软件的办法。java
面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近类似的操做逻辑和操做 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提升软件开发效率的做用。python
面向对象的理解: - 面向对象是一种设计思想 1. 符合人们的思考习惯 2. 把执行者变成指挥者 3. 简化功能,把复杂的事情简单化 - 想完成一个事,找具备这样功能的对象 - 若是能找到,调用这个对象的功能,完成这个事 - 若是找不到,建立具备这样功能的对象,再调用完成这个事
面向对象有三大特征: 1. 封装 2. 继承 3. 多态
面向对象编程的2个很是重要的概念:类和对象数据库
对象是面向对象编程的核心,在使用对象的过程当中,为了将具备共同特征和行为的一组对象抽象定义,提出了另一个新的概念——类编程
类就至关于制造飞机时的图纸,用它来进行建立的飞机就至关于对象设计模式
- 类是对事务的描述,是抽象的。 - 对象是类的具体体现。 - 类对事务的描述:属性(名词)和行为(动词)
具备相同属性和行为事物的统称安全
某一个具体事物的存在 ,在现实世界中能够是看得见摸得着的app
小总结:类就是建立对象的模板函数
拥有相同(或者相似)属性和行为的对象均可以抽像出一个类测试
类是对事务的描述。 一、属性 二、行为 如今呢,要描述汽车这个类。 一、类名 Car 大驼峰命名法 二、属性 三、行为(语法与函数同样,这里叫方法) run stop 至少有一个参数,名字任意,通常都是self 对象是类的具体体现 建立对象 名字 = 类()
class Car: def run(self): print('汽车奔跑中。。。。。。') def stop(self): print('汽车急刹中。。。。。。') wlhgs = Car() wlhgs.run() wlhgs.stop() bcs = Car() bm7 = Car() ad8 = Car() #每次建立都是新的对象 print(wlhgs,id(wlhgs)) print(bcs,id(bcs)) #虽然每一个对象都有类里方法,可是实际上是一个方法,地址同样。 print(id(wlhgs.run)) print(id(bcs.run))
#建立类 class Car: def run(self): print('汽车奔跑中。。。。。。') def stop(self): print('汽车急刹中。。。。。。') def haha(self): print('哈哈。。。。。。。') #建立对象-实例 bmw = Car() #调用/执行实例方法 bmw.run() #为对象实例设置一个属性 bmw.color = '黑色' #获取对象实例的属性 print('颜色:%s'%(bmw.color)) bmw.brand = '宝马7系' print('系列:%s'%(bmw.brand)) aodi = Car() #此时aodi对象实例并无color属性 #print(aodi.color)
在上一小节的demo中,咱们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想若是再次建立一个对象的话,确定也须要进行添加属性,显然这样作很费事,那么有没有办法可以在建立对象的时候,就顺便把车这个对象的属性给设置呢?this
在python中相似于这样格式__名字__()的方法叫作魔法方法 __init___ 做用: 在对象建立的时候为对象添加属性--实例属性 特色: 在建立对象的时候,自动会被调用 self:当前对象实例,哪一个对象调用了这个方法,self就是哪一个对象
class Car: def __init__(self): print('__init__......') self.color = '黑色' self.brand = '哈弗H6' def run(self): print('汽车奔跑中。。。。。。%s,%s'%(self,id(self))) def stop(self): print('汽车急刹中。。。。。。') # #mumaren = Car() #mumaren.run() #print('%s,%s'%(mumaren,id(mumaren))) haval1 = Car() print(haval1.color) print(haval1.brand) haval2 = Car() print(haval2.color) print(haval2.brand)
class Car: def __init__(self,color,brand): print('__init__......') self.color = color self.brand = brand def run(self): print('汽车奔跑中。。。。。。%s,%s'%(self,id(self))) def stop(self): print('汽车急刹中。。。。。。') haval1 = Car('白色','哈弗h7') print(haval1.color) print(haval1.brand) haval2 = Car('银灰色','哈弗h9') print(haval2.color) print(haval2.brand) #对象是可变类型 haval3 = haval2 haval3.color = '黑色' print(haval2.color)
__str__ 何时调用? 对象转换成字符串 str(对象) 测试的时候,打印对象的信息 格式: def __str__(self): return 字符串 print打印的时候,默认就将内容转成字符串
class Car: def __init__(self,color,brand): print('__init__......') self.color = color self.brand = brand def __str__(self): print('__str__......') return 'Car color:%s,brand:%s'%(self.color,self.brand) def run(self): print('汽车奔跑中。。。。。。') def stop(self): print('汽车急刹中。。。。。。') def show(self): print('color:%s,brand:%s'%(self.color,self.brand)) haval1 = Car('白色','哈弗h7') print(haval1) print(id(haval1)) #print(str(haval1)) #haval1.show()
- self表示是当前对象,能够理解为本身 - 能够把self当作C++中类里面的this指针同样理解,就是对象自身的意思 - 某个对象调用其方法时,python解释器会把这个对象做为第一个参数传递给self,因此开发者只须要传递后面的参数便可
示例属性以下:
示例方法以下:
#定义`地瓜`类 class SweetPotato: '这是烤地瓜的类' #定义初始化方法 def __init__(self): self.cookedLevel = 0 self.cookedString = "生的" self.condiments = []
#烤地瓜方法 def cook(self, time): self.cookedLevel += time if self.cookedLevel > 8: self.cookedString = "烤成灰了" elif self.cookedLevel > 5: self.cookedString = "烤好了" elif self.cookedLevel > 3: self.cookedString = "半生不熟" else: self.cookedString = "生的"
mySweetPotato = SweetPotato() print(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString) print(mySweetPotato.condiments)
print("------接下来要进行烤地瓜了-----") mySweetPotato.cook(4) #烤4分钟 nt(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString)
运行结果为:
def __str__(self): msg = self.cookedString + " 地瓜" if len(self.condiments) > 0: msg = msg + "(" for temp in self.condiments: msg = msg + temp + ", " msg = msg.strip(", ") msg = msg + ")" return msg def addCondiments(self, condiments): self.condiments.append(condiments)
定义类: 属性 一、cookedLevel int 0 二、cookedString str '生的' 三、condiments [] [] 方法 一、初始化属性 __init__ cookedLevel,cookedString,condiments 二、烤地瓜 cook time 三、加调料 addCondiment condiment 四、地瓜的信息 __str__
完整的代码以下:
class SweetPotato: "这是烤地瓜的类" #定义初始化方法 def __init__(self): self.cookedLevel = 0 self.cookedString = "生的" self.condiments = [] #定制print时的显示内容 def __str__(self): msg = self.cookedString + " 地瓜" if len(self.condiments) > 0: msg = msg + "(" for temp in self.condiments: msg = msg + temp + ", " msg = msg.strip(", ") msg = msg + ")" return msg #烤地瓜方法 def cook(self, time): self.cookedLevel += time if self.cookedLevel > 8: self.cookedString = "烤成灰了" elif self.cookedLevel > 5: self.cookedString = "烤好了" elif self.cookedLevel > 3: self.cookedString = "半生不熟" else: self.cookedString = "生的" #添加配料 def addCondiments(self, condiments): self.condiments.append(condiments) # 用来进行测试 mySweetPotato = SweetPotato() print("------有了一个地瓜,尚未烤-----") print(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString) print(mySweetPotato.condiments) print("------接下来要进行烤地瓜了-----") print("------地瓜经烤了4分钟-----") mySweetPotato.cook(4) #烤4分钟 print(mySweetPotato) print("------地瓜又经烤了3分钟-----") mySweetPotato.cook(3) #又烤了3分钟 print(mySweetPotato) print("------接下来要添加配料-番茄酱------") mySweetPotato.addCondiments("番茄酱") print(mySweetPotato) print("------地瓜又经烤了5分钟-----") mySweetPotato.cook(5) #又烤了5分钟 print(mySweetPotato) print("------接下来要添加配料-芥末酱------") mySweetPotato.addCondiments("芥末酱") print(mySweetPotato)
运行结果为:
home类: 属性 一、面积 方法 二、存放家具 bed类: 属性: 一、面积 二、名字
#定义一个home类 class Home: def __init__(self, area): self.area = area #房间剩余的可用面积 #self.light = 'on' #灯默认是亮的 self.containsItem = [] def __str__(self): msg = "当前房间可用面积为:" + str(self.area) if len(self.containsItem) > 0: msg = msg + " 容纳的物品有: " for temp in self.containsItem: msg = msg + temp.getName() + ", " msg = msg.strip(", ") return msg #容纳物品 def accommodateItem(self,item): #若是可用面积大于物品的占用面积 needArea = item.getUsedArea() if self.area > needArea: self.containsItem.append(item) self.area -= needArea print("ok:已经存放到房间中") else: print("err:房间可用面积为:%d,可是当前要存放的物品须要的面积为%d"%(self.area, needArea)) #定义bed类 class Bed: def __init__(self,area,name = '床'): self.name = name self.area = area def __str__(self): msg = '床的面积为:' + str(self.area) return msg #获取床的占用面积 def getUsedArea(self): return self.area def getName(self): return self.name #建立一个新家对象 newHome = Home(100)#100平米 print(newHome) #建立一个床对象 newBed = Bed(20) print(newBed) #把床安放到家里 newHome.accommodateItem(newBed) print(newHome) #建立一个床对象 newBed2 = Bed(30,'席梦思') print(newBed2) #把床安放到家里 newHome.accommodateItem(newBed2) print(newHome)
若是有一个对象,当须要对其进行修改属性时,有2种方法
对象名.属性名 = 数据 ---->直接修改 对象名.方法名() ---->间接修改
为了更好的保存属性安全,即不能随意修改,通常的处理方式为
将属性定义为私有属性 添加一个能够调用的方法,供调用
私有化某些敏感的数据属性,
对外提供可访问的接口(方法),
这也是一种封装
在java,C#中,要求:
一、全部的属性私有化 二、对外提供get,set
python没要求。
若是某些属性就是不让外部访问,直接__属性名 私有化 是否提供对外访问的接口,根据须要。
class Person: def __init__(self): self.__age = 18 def getAge(self): #判断一些业务逻辑,若是符号要去,给你数据,不符合,不给。 return self.__age; def setAge(self,age): if age<0 or age>120: print('年龄不符合要求。。。。。。') else: self.__age = age laowang = Person() print(laowang.getAge()) laowang.setAge(-40) print(laowang.getAge())
当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
import time class Animal: # 初始化方法 # 建立完对象后会自动被调用 def __init__(self, name): print('__init__方法被调用') self.__name = name #对象在被垃圾回收机制的时候调用这个方法,来释放资源。除非有特殊要求,通常不要重写。 #在关闭数据库链接对象的时候,能够在这里,释放资源 def __del__(self): print('__del__......') wangcai = Animal('旺财') xiaoqiang = wangcai del wangcai print('*'*50) del xiaoqiang time.sleep(10) print('over......')
将共性的内容放在父类中,子类只须要关注本身特有的内容
python中全部的内容都是对象,全部的对象都直接或间接继承了object
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中即可以描述为猫和狗继承自动物
将共性的内容放在父类中
子类只关注本身特有的内容
扩展性高,代码更简洁
# 定义一个父类 class Dog(object): def __init__(self,name,color): self.name = name self.color = color def run(self): print('%s %s run......'%(self.name,self.color)) # 定义一个子类,继承Dog类 class TaiDi(Dog): def setName(self,name): self.name = name taidi = TaiDi('泰迪','棕色') taidi.run() #泰迪 棕色 run...... taidi.setName('泰迪弟') taidi.run() #泰迪弟 棕色 run......
总结
class Animal(object): def __init__(self, name='动物', color='白色'): self.__name = name self.color = color def __test(self): print(self.__name) print(self.color) def test(self): print(self.__name) print(self.color) class Dog(Animal): def dogTest1(self): #print(self.__name) #不能访问到父类的私有属性 print(self.color) def dogTest2(self): #self.__test() #不能访问父类中的私有方法 self.test() A = Animal() #print(A.__name) #程序出现异常,不能访问私有属性 print(A.color) #A.__test() #程序出现异常,不能访问私有方法 A.test() print("------分割线-----") D = Dog(name = "小花狗", color = "黄色") D.dogTest1() D.dogTest2()
总结
多继承:这个类继承了多个父类,是有顺序 继承具备传递性 继承以后,此对象的方法或属性就增长。 调用的时候,注意是否本身有,或者父类有。
class A(object): def a(self): print('a......') class B: def b(self): self.c() #这里又调用C()中的c print('b......') class C(A,B): def c(self): print('c......') # #laowang = C() #laowang.a() #laowang.b() #laowang.c() x = C() x.b() #c...... #b...... #获取父类 print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>) print(A.__bases__) #(<class 'object'>,) #列举,这个类和继承类的结构。调用方法的顺序**(类名.__mro__)** print(C.__mro__) #(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
class A(object): def haha(self): print('haha a......') class B(A): def haha(self): print('哈哈 b......') b = B() b.haha()
class C2: def haha(self): print('haha 2......') class C3: def haha(self): print('haha 3......') class C4(C3,C2): def haha(self): #super().haha() C2.haha(self) print('haha 4......') laowang= C4() laowang.haha() print(C4.__mro__)
class Fu: def __init__(self,name,age): print('fu...%s'%(id(self))) self.name = name self.age = age class Zi(Fu): def __init__(self,name,age,sex): print('zi...%s'%(id(self))) #super().__init__(name,age) #这是方法一 Fu.__init__(self,name,age) #这是方法二 self.sex = sex def show(self): print('%s,%s,%s'%(self.name,self.age,self.sex)) zi = Zi('老王',43,'男') zi.show() print(id(zi))
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。
首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。
在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。
python既能够说支持多态,也能够说不支持多态 一、支持多态 python的弱类型,变量的类型是根据赋值的类型判断的,值是什么类型,变量就是什么类型 这就是多态 二、不支持多态 由于python是弱类型语言,没有要求类型,不彻底符合多态的定义。
class F1(object): def show(self): print('F1.show') class S1(F1): def show(self): print('S1.show') class S2(F1): def show(self): print('S2.show') def func(obj): obj.show() #print(type(obj)) s1_obj = S1() func(s1_obj) s2_obj = S2() func(s2_obj) f1 = F1() func(f1)
class People(object): name = 'Tom' #公有的类属性 __age = 12 #私有的类属性 p = People() print(p.name) #正确 print(People.name) #正确 print(p.__age) #错误,不能在类外经过实例对象访问私有的类属性 print(People.__age) #错误,不能在类外经过类对象访问私有的类属性
class People(object): address = '山东' #类属性 def __init__(self): self.name = 'xiaowang' #实例属性 self.age = 20 #实例属性 p = People() p.age =12 #实例属性 print(p.address) #正确 print(p.name) #正确 print(p.age) #正确 print(People.address) #正确 print(People.name) #错误 print(People.age) #错误
class People(object): country = 'china' #类属性 print(People.country) p = People() print(p.country) p.country = 'japan' print(p.country) #实例属性会屏蔽掉同名的类属性 print(People.country) del p.country #删除实例属性 print(p.country)
总结
实例方法/对象方法,有一个参数,通常叫self 在使用的时候,对象.方法名(实参) self不须要手动传值,默认将当前对象传递过去给self
语法: @classmethod def 方法名(cls,x,y,z...): 语句 调用: 对象名. 类名. cls:类对象 类也是对象,type的对象, 在类方法中,设置的属性,是类属性,全部对象共享。 何时用类方法呢? 一、想经过类直接访问的方法 二、想经过方法来设置或者修改类属性
class People(object): country = 'china' #类方法,用classmethod来进行修饰 @classmethod def getCountry(cls): return cls.country @classmethod def setCountry(cls,country): cls.country = country p = People() print(p.getCountry()) #china #能够用过实例对象引用 print(People.getCountry())#china #能够经过类对象引用 p.setCountry('japan') print(p.getCountry()) #japan
语法: @staticmethod def 名(形参): 语句 实例方法必须至少有一个参数放在第一个,通常叫self 类方法必须至少有一个参数放在第一个,通常叫cls 静态方法能够没有参数,也能够有参数,可是没法直接获取类对象和实例对象 因此通常静态方法里的功能,不与对象相关
class Dog: age = 18 def __init__(self,name): self.name = name @staticmethod def show(): print('show.....%s'%(Dog.age)) d = Dog('旺财') d.show() #show.....18 - 静态方法中不须要额外定义参数 - 所以在静态方法中引用类属性的话,必须经过类对象来引用
设计模式六大原则(1):单一职责原则
即一个类只负责一项职责设计模式六大原则(2):里氏替换原则
全部引用基类的地方必须能透明地使用其子类的对象设计模式六大原则(3):依赖倒置原则
高层模块不该该依赖低层模块,两者都应该依赖其抽象;抽象不该该依赖细节;细节应该依赖抽象。设计模式六大原则(4):接口隔离原则
客户端不该该依赖它不须要的接口;一个类对另外一个类的依赖应该创建在最小的接口上。设计模式六大原则(5):迪米特法则
一个对象应该对其余对象保持最少的了解。尽可能下降类与类之间的耦合。设计模式六大原则(6):开闭原则
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
1.建立型模式
主要目的:建立对象
共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2.结构型模式
主要目的:对象的组成和对象的关系
共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
3.行为型模式
主要目的:对象的行为,对象能作什么
共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
组成:
实例:
''' 抽象角色(父类):它通常是具体产品继承的父类或者实现的接口 ''' class Car(object): def move(self): pass def stop(self): pass ''' 具体产品角色(继承抽象角色):工厂类所建立的对象就是此角色的实例。 ''' class H1(Car): def move(self): print('哈弗h1 move......') def stop(self): print('哈弗h1 stop......') class H9(Car): def move(self): print('哈弗h9 move......') def stop(self): print('哈弗h9 stop......') class H7(Car): def move(self): print('哈弗h7 move......') def stop(self): print('哈弗h7 stop......') class H6(Car): def move(self): print('哈弗h6 move......') def stop(self): print('哈弗h6 stop......') ''' 工厂类角色:这是本模式的核心,含有必定的逻辑判断,用来建立产品 ''' class CarFactory: @classmethod def createCar(cls,name): car = None if name=='哈弗H1': car = H1() elif name=='哈弗H9': car = H9() elif name=='哈弗H7': car = H7() elif name=='哈弗H6': car = H6() return car ''' 主代码 ''' name = input('请输入要购买的车型:') car = CarFactory.createCar(name) if car!=None: car.move() car.stop() else: print('没有。。。。。。。')
说明:
工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体,4s店只负责销售,汽车厂只负责制造
总结:
对象建立比较复杂的时候,能够考虑使用简单工厂
''' 抽象角色(父类):它通常是具体产品继承的父类或者实现的接口 ''' class Car(object): def move(self): pass def stop(self): pass ''' 具体产品角色(继承抽象角色):工厂类所建立的对象就是此角色的实例。 ''' class H1(Car): def move(self): print('哈弗h1 move......') def stop(self): print('哈弗h1 stop......') class H9(Car): def move(self): print('哈弗h9 move......') def stop(self): print('哈弗h9 stop......') class H7(Car): def move(self): print('哈弗h7 move......') def stop(self): print('哈弗h7 stop......') ''' 抽象工厂类角色 ''' class CarFactory: @classmethod def createCar(cls,name): pass ''' 具体工厂类角色:这是本模式的核心,含有必定的逻辑判断,用来建立产品 ''' class H1Factory(CarFactory): @classmethod def createCar(cls,name): return H1() class H9Factory(CarFactory): @classmethod def createCar(cls,name): return H9() class H7Factory(CarFactory): @classmethod def createCar(cls,name): return H7() ''' 主代码 ''' name = input('请输入要购买的车型:') car = None if name=='哈弗H1': car = H1Factory.createCar(name) elif name=='哈弗H9': car = H9Factory.createCar(name) if car!=None: car.move() car.stop() else: print('没有。。。。。。。')
总结:
工厂方法模式的优势和缺点
a1 = A() 建立对象的步骤 一、首先调用__new__获得一个对象 二、调用__init__为对象添加属性 三、将对象赋值给变量
class A(object): def __init__(self): print("这是 init 方法") def __new__(cls): print(id(cls)) print("这是 new 方法") return object.__new__(cls) a1 = A() print(a1) #7214424 #这是 new 方法 #这是 init 方法 #<__main__.A object at 0x0000000000BDEB00> print(id(a1)) #12446464 print(id(A)) #7214424
总结
确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象建立型模式。
一、单例模式Singleton 在项目中某些对象,只有一个,能够一直使用。 若是再次实例化,会很占资源和时间。 因此,这样的对象就须要设计成单例模式。 二、原型模式Prototype 能够实例化多个对象,每一个都是新的,之前设计的类都是原型模式 object.__new__(cls): 表示建立了一个实例对象
class Singleton: #表示对象是否被建立 None:没有,其它:已经建立 __instance = None def __new__(cls): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance s1 = Singleton() s2 = Singleton() s3 = Singleton() print(id(s1)) #18342968 print(id(s2)) #18342968 print(id(s3)) #18342968
class Singleton: #表示对象是否被建立 None:没有,其它:已经建立 __instance = None #表示是否是第一次调用init: True:第一次调用 False:不是第一次调用 __firstInit = True def __init__(self,*args,**kwargs): if Singleton.__firstInit: self.args = args self.kwargs = kwargs Singleton.__firstInit=False def __new__(cls,*args,**kwargs): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance s1 = Singleton('老王',10,'add','',money=12345) print(id(s1)) #8514472 print(s1.args[0]) #老王 print(s1.args[2]) #add print(s1.kwargs['money'])#12345 s2 = Singleton('旺财') print(id(s2)) #8514472 print(s2.args[0]) #老王 print(s2.args[2]) #add print(s2.kwargs['money'])#12345 s3 = Singleton() print(s3.kwargs['money'])#12345