OOA:(Object Oriented Analysis)面向对象分析。系统分析师。UML中的用例图
OOD:(Object Oriented Design)面向对象设计。系统架构师。UML中的类图、序列图
OOP:(Object Oriented Programming) 面向对象编程。程序猿。UML中的流程图
面向对象中有6大原则,23个设计模式
开闭原则:对修改关闭;对扩展开放(对于函数,使用装饰器来扩展。对于类,使用继承来扩展)
里氏替换原则:一个功能如果父类适用,那么子类也适用;反之则未必(子类适用的功能,父类不一定适用)
如果一个类作用于某个父类,则它一定可以作用于对应的子类;反之未必(如果一个类作用于子类,则它未必能作用于父类)
如图:法海抓妖,蛇妖是妖的子类,所以法海碰到蛇妖一定要抓
反之,许仙喜欢白蛇,白蛇是蛇妖的子类,但是许仙不一定喜欢蛇妖
根据这个原则:如果设计两个类之间的依赖、通信关系,应该尽量往父类发展。
class 子类名(父类名):
子类的具体实现
父类中所有非私有的属性和方法,在子类中可以访问
子类可以访问父类的方法
# 父类:动物
class Animal:
def eat(self):
print('Animal eat')
# 子类:狗
class Dog(Animal):
pass
#
dog1 = Dog()
dog1.eat()
子类可以重写父类的方法
# 父类:动物
class Animal:
def eat(self):
print('Animal eat')
# 子类:狗
class Dog(Animal):
def eat(self):
print('Dog eat')
#
dog1 = Dog()
dog1.eat()
子类还可以主动调用父类的方法
# 父类:动物
class Animal:
def eat(self):
print('Animal eat')
# 子类:狗
class Dog(Animal):
def eat(self):
super().eat() # 调用父类的方法
print('Dog eat')
#
dog1 = Dog()
dog1.eat()
注意:super()是在类里面调用,不能在类外面调用。如果这样写,会报错:
dog2 = Dog()
dog2.super().eat()
Python中的规定,如果一个类没有明确指定继承的父类,默认继承object类。
class Animal:
def eat(self):
print('Animal eat')
等同于
class Animal(object):
def eat(self):
print('Animal eat')
前面一种写法(不继承任何父类)称为经典类(马上会过时,不建议使用)
后面一种写法(继承任意一个类,比如object)称为新式类。
以后,都建议写成新式类。
如果在子类中,想要调用父类的__init__或__del__方法。通过:
父类名.init(参数)
父类名.del()
# 父类:动物
class Animal(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'name:' + self.name
def __del__(self):
print('Animal del')
# 子类:狗
class Dog(Animal):
def __init__(self, name):
# 尝试调用父类的__init__方法
Animal.__init__(self,name)
def __del__(self):
# 尝试调用父类的__del__方法
Animal.__del__(self)
#
dog1 = Dog('旺财')
print(dog1)
如果父类中有私有属性和私有的方法,子类不能访问。
# 父类:动物
class Animal(object):
def __init__(self, name):
self.name = name
self.__age = 0
def __info(self):
print(self.__age)
# 子类:狗
class Dog(Animal):
def __init__(self, name):
# 尝试调用父类的__init__方法
Animal.__init__(self,name)
def info(self):
print(self.__age)
self.__info()
dog1 = Dog('旺财')
dog1.info()
1 继承。子类继承父类。如果两个类之间可以用“是一个”(is a)来描述,可以使用继承关系:比如:
狗是一个动物
class Animal(object):
pass
class Dog(Animal):
pass
2 包含。大类包含小类。如果两个类之间可以用“有一个”(has a)来描述,可以使用包含关系。比如:
狗有一条腿
class Dog(Animal):
def __init__(self):
self.leg = Leg()
class Leg(object):
pass
3 通信。如果两个类之间可以通过动词连接起来,可以使用通信关系,比如:
人养狗、狗咬人
class Dog(Animal):
def __init__(self):
self.leg = Leg()
# 狗咬人
def bid(self, man):
print(self.name + '咬' + man.get_name())
class Man(Animal):
def __init__(self):
self.leg = Leg()
# 人养狗
def feed(self, dog):
print(self.name + '养' + dog.get_name())
一个子类可以继承多个父类
C++、Python是有多继承。Java是没有多继承的
骡子是驴和马的杂交。就可以认为是骡子是驴和马的子类。
多继承的格式:
class 子类(父类1, 父类2, 父类3):
方法中的代码
比如:
class Base1(object):
def test1(self):
print('---Base1---')
class Base2(object):
def test2(self):
print('---Base2---')
# Sub是Base1和Base2的子类
class Sub(Base1, Base2):
pass
sub = Sub()
sub.test1()
sub.test2()
class Animal(object):
# 初始化
def __init__(self):
print('Animal init')
class Horse(Animal):
# 初始化
def __init__(self):
Animal.__init__(self) #调用父类的__init__方法
print('Horse init')
class Lv(Animal):
# 初始化
def __init__(self):
Animal.__init__(self) #调用父类的__init__方法
print('Lv init')
class Luo(Horse, Lv):
# 初始化
def __init__(self):
Horse.__init__(self)
Lv.__init__(self)
print('Luo init')
print('--------------------------')
luo = Luo()
运行的结果:
会发现Animal init调用了两次。囧么办?
C++:使用虚拟继承。
Java:不允许使用多继承
Pyton:super
class Animal(object):
# 初始化
def __init__(self):
print('Animal init')
class Horse(Animal):
# 初始化
def __init__(self):
#Animal.__init__(self) #调用父类的__init__方法
super(Horse, self).__init__()
print('Horse init')
class Lv(Animal):
# 初始化
def __init__(self):
#Animal.__init__(self) #调用父类的__init__方法
super(Lv, self).__init__()
print('Lv init')
class Luo(Horse, Lv):
# 初始化
def __init__(self):
#Horse.__init__(self)
#Lv.__init__(self)
super(Luo, self).__init__()
print('Luo init')
luo = Luo()
运行的结果
不同的事物,对同一个操作所作出的不同响应
外壳医生、屠夫、演员。Cut…
与其他编程语言(Java)比较起来,Python中的多态的概念,大大的弱化。
class Animal(object):
def eat(self):
print('Animal eat')
class Dog(Animal):
def eat(self):
print('Dog eat')
class Man(Animal):
def eat(self):
print('Man eat')
class Woman(Animal):
def eat(self):
print('Woman eat')
def do_eat(obj):
obj.eat()
dog1 = Dog()
man1 = Man()
woman1 = Woman()
do_eat(dog1)
do_eat(man1)
do_eat(woman1)
isinstance(obj, Cls)判断某个对象obj是否某个类Cls(或它的子类)的实例
如果是则返回True 如果不是则返回False
def do_eat(obj):
if(isinstance(obj, Animal)):
obj.eat()
类属性是指一个类中的所有对象都共用的属性。又称为静态属性
实例属性是指类的某个对象独有的属性,又称为非静态属性
比如:每条狗都有4条腿
比如:你们家多少人?4个:我、爸、妈、狗
如果要描述实例属性,使用“对象名. 属性名”去描述(dog1.name、self.name)
如果要描述类属性,使用“类名.属性名”去描述。
class Dog(object):
# 类属性
_count = 0
def __init__(self,name):
self._name = name
Dog._count += 1
def __str__(self):
return self._name + "说:目前总共有" + str(Dog._count) + "只狗"
dog1 = Dog('旺财')
dog2 = Dog('小白')
dog3 = Dog('雪梨')
print(dog3)
print(dog2)
print(dog1)
注意:类属性也可以使用“对象名.属性名”去访问,但一般不建议。
思考:下面哪个是不能正常访问的?
类名.类属性 类名.实例属性 对象名.类属性 对象名.实例属性
如果要实现类方法,需要:
1 把实例方法的第1个参数从self改为cls,表示当前类
2 在类方法前添加@classmethod
3 外部调用类方法的时候,使用“类名.方法名()”
class Dog(object):
# 类属性
_count = 0
def __init__(self,name):
self._name = name
Dog._count += 1
def __str__(self):
return self._name + "说:目前总共有" + str(Dog._count) + "只狗"
# 增加狗的数量 类方法
@classmethod # add_one = classmethod(add_one)
def add_one(cls):
cls._count += 1
dog1 = Dog('旺财')
dog2 = Dog('小白')
print(dog2)
Dog.add_one()
print(dog2)
Python中一切皆对象。类也是一个对象。比如前面的:狗类是一个对象,动物类也是一个对象。这些对象一般称为“类对象”(Class对象),“类对象”所属的类称为“类类”(Class类)。就是,在系统中会有如下的定义:
class Class(object):
…..
当我们写
class Dog(object):
….
实际上是写了
Dog = Class()
注意一点:我们之前调用的__init__的写法是:
class Horse(Animal):
# 初始化
def __init__(self):
Animal.__init__(self) #调用父类的__init__方法
print('Horse init')
有些独立的代码,可能和类的属性、方法并没有什么关系。
但是和类本身又有关系。这些代码封装到哪里比较合适?
1 封装到独立的函数中。与面向对象的思维本身有所冲突
2 封装到类的方法中,但是self、cls参数感觉好像没有关系
3 封装到类的独立的静态方法中
class Dog(object):
# 类属性
_count = 0
def __init__(self,name):
self._name = name
Dog._count += 1
# 增加狗的数量 类方法
@classmethod # add_one = classmethod(add_one)
def add_one(cls):
cls._count += 1
# 对象方法
def bark2(self):
print('旺旺')
# 类方法
@classmethod
def bark3(cls):
print('旺旺')
# 静态方法
@staticmethod
def bark4():
print('旺旺')
# 独立的函数
def bark1():
print('旺旺')
bark1()
#bark()
dog1 = Dog('旺财')
dog1.bark2()
Dog.bark3()
Dog.bark4()
上面的bark1()函数、bark2()对象方法、bark3()类方法、bark4()静态方法,都可以实现类似的功能。
之前接触过的前后双下划线的方法:
_init_(初始化)
_str_(描述对象)
_del_(删除销毁对象)
class Dog(object):
def __init__(self):
print('init')
def __str__(self):
return 'str'
def __del__(self):
print('del')
def __new__(cls):
print('new')
dog1 = Dog() # __init__
print(dog1) # __str__
del dog1 # __del__
print('------')
运行程序,会发现:
证明只有__new__()被执行,init()没有被执行。
如何才能让__init__()被执行?需要让__new__返回一个值
def __new__(cls):
print('new')
return object.__new__(cls) # 让父类的__new__()方法去创建该对象
# __new__的返回值会传递到__init__()的第一个参数中
_new_()的操作实际上是创建对象。init()的操作是初始化。init()的第一个参数是self,描述对象本身,说明当__init__被调用的时候,对象已经创建好了,现在知道,对象是在__new__()里面去创建的。
当用户调用Dog()创建一个实例的时候,到底内部做了什么事情?
1 先调用__new__方法来创建并返回一个对象,用一个变量保存该对象,然后把该对象传递到__init__方法中作为第一个参数。以便初始化
2 调用__init__方法。初始化该对象
3 返回该对象
实现原理大致如下:
def unknown():
obj = __new__(Dog)
__init__(obj)
return obj
面向对象有23种设计模式。创建型模式(5种)、结构型模型(7种)、行为型模型(11种)
单例模式属于创建型模型。
在某个系统中,一个类的对象只有一个。
class Sun(object):
pass
sun1 = Sun()
sun2 = Sun()
print(id(sun1))
print(id(sun2))
print(id(sun1) == id(sun2))
假设有一个类Sun(太阳)。太阳既然是唯一的,这里打印出来的结果应该是True
思路:创建类的时刻只有一次
如果是第一次创建对象,直接创建即可
如果不是第一次创建对象,返回之前创建过的那个
此时,就需要重写__new__方法。
class Sun(object):
_instance = None
# 重写__new__方法
def __new__(cls):
if cls._instance == None:
# 如果该类还没创建对象 就调用父类的__new__方法创建该对象
cls._instance = object.__new__(cls)
return cls._instance
else:
# 如果该类已经创建了对象 则返回该对象本身
return cls._instance
假如给类设置一个属性(姓名)
class Sun(object):
_instance = None
# 重写__new__方法
def __new__(cls, name):
if cls._instance == None:
# 如果该类还没创建对象 就调用父类的__new__方法创建该对象
cls._instance = object.__new__(cls)
return cls._instance
else:
# 如果该类已经创建了对象 则返回该对象本身
return cls._instance
def __init__(self, name):
self._name = name
def __str__(self):
return self._name
sun1 = Sun('喜洋洋')
print(sun1)
print(id(sun1))
sun2 = Sun('懒羊羊')
print(sun2)
print(id(sun2))
运行的结果
class Sun(object):
_instance = None
_init_flag = False
# 重写__new__方法
def __new__(cls, name):
if cls._instance == None:
# 如果该类还没创建对象 就调用父类的__new__方法创建该对象
cls._instance = object.__new__(cls)
return cls._instance
else:
# 如果该类已经创建了对象 则返回该对象本身
return cls._instance
def __init__(self, name):
if Sun._init_flag == False:
self._name = name
Sun._init_flag = True
def __str__(self):
return self._name
项目需求(二)
通用类开发
目录:app/common
状态类Status, 文件status.py ,
包括成功和失败两种状态,每个状态包含状态码和状态信息两个属性。
如成功状态调用方法Status.SUCCESS.status Status.SUCCESS.message
失败状态调用方法:Status.ERROR.status Status.ERROR.message
SUCCESS 属性 status 值 200000,message 值 Success
ERROR 属性 status 值 200400,message 值 Error
响应结果类 Result,文件 result.py,包括成功和失败两种返回结果。
{
“status”: status,
“message”: message,
“data”: data
}
URL:https://gitee.com/yuanbaonet/master_python/tree/baoai_python_v9/
对应版本:baoai_python_v9
对应文件:sample/python/p9.py