python面向对象
初识面向对象:
class 类名:
def __init__(self,参数1,参数2):
self.对象的属性1 = 参数1
self.对象的属性2 = 参数2
def 方法名(self):pass
def 方法名2(self):pass
对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西
#类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
#括号里传参数,参数不需要传self,其他与init中的形参一一对应
#结果返回一个对象
对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
组合:
# 组合是什么有什么的关系,如:人有生日,人有武器,后者必须是前者的属性
# 一个对象的属性是另外一个类的对象
class Dog: # 定义一个狗类
def __init__(self, name, breed, aggressivity, life_value):
self.name = name # 每一只狗都有自己的昵称;
self.breed = breed # 每一只狗都有自己的品种;
self.aggressivity = aggressivity # 每一只狗都有自己的攻击力;
self.life_value = life_value # 每一只狗都有自己的生命值;
def bite(self, people):
people.life_value -= self.aggressivity
class Person: # 定义一个人类
def __init__(self, name, aggressivity, life_value, money):
self.name = name # 每一个角色都有自己的昵称;
self.aggressivity = aggressivity # 每一个角色都有自己的攻击力;
self.life_value = life_value # 每一个角色都有自己的生命值;
self.money = money # 每一个角色都有自己的金钱
def attack(self, dog):
dog.life_value -= self.aggressivity
def get_weapon(self, weapon_obj):
if self.money > weapon_obj.price:
self.money -= weapon_obj.price # 金老板花钱买武器
self.weapon = weapon_obj # 金老板装备打狗棒
self.aggressivity += weapon_obj.aggr # 金老板的攻击力增加了
class Weapon: # 定义一个武器类
def __init__(self, name, price, aggr):
self.name = name # 武器的名字
self.price = price # 武器的价格
self.aggr = aggr # 武器的攻击力
dgb = Weapon('打狗棒', 99.8, 100)
boss_gold = Person('金老板', 5, 250, 100)
huang = Dog('大黄', '藏獒', 100, 3000)
boss_gold.get_weapon(dgb)
boss_gold.attack(huang)
print(huang.life_value)
继承:
# 继承是:什么是什么的关系.如:老师是人,人是动物
# 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
# python中类的继承分为:单继承和多继承
class ParentClass1: # 定义父类
pass
class ParentClass2: # 定义父类
pass
class SubClass1(ParentClass1): # 单继承,基类是ParentClass1,派生类是SubClass
pass
class SubClass2(ParentClass1, ParentClass2): # python支持多继承,用逗号分隔开多个继承的类
pass
# __base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
# 提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类
在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时
我们不可能从头开始写一个类B,这就用到了类的继承的概念。
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
class Animal:
'''
人和狗都是动物,所以创造一个Animal基类
'''
def __init__(self, name, aggressivity, life_value):
self.name = name # 人和狗都有自己的昵称;
self.aggressivity = aggressivity # 人和狗都有自己的攻击力;
self.life_value = life_value # 人和狗都有自己的生命值;
def eat(self):
print('%s is eating'%self.name)
class Dog(Animal):
pass
class Person(Animal):
pass
egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
egg.eat()
ha2.eat()
复制代码
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.
派生
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
复制代码
class Animal:
'''
人和狗都是动物,所以创造一个Animal基类
'''
def __init__(self, name, aggressivity, life_value):
self.name = name # 人和狗都有自己的昵称;
self.aggressivity = aggressivity # 人和狗都有自己的攻击力;
self.life_value = life_value # 人和狗都有自己的生命值;
def eat(self):
print('%s is eating'%self.name)
class Dog(Animal):
'''
狗类,继承Animal类
'''
def bite(self, people):
'''
派生:狗有咬人的技能
:param people:
'''
people.life_value -= self.aggressivity
class Person(Animal):
'''
人类,继承Animal
'''
def attack(self, dog):
'''
派生:人有攻击的技能
:param dog:
'''
dog.life_value -= self.aggressivity
egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
print(ha2.life_value)
print(egg.attack(ha2))
print(ha2.life_value)
复制代码
注意:像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.
在python3中,子类执行父类的方法也可以直接用super方法.
class Animal:
'''
人和狗都是动物,所以创造一个Animal基类
'''
def __init__(self, name, aggressivity, life_value):
self.name = name # 人和狗都有自己的昵称;
self.aggressivity = aggressivity # 人和狗都有自己的攻击力;
self.life_value = life_value # 人和狗都有自己的生命值;
def eat(self):
print('%s is eating'%self.name)
class Dog(Animal):
'''
狗类,继承Animal类
'''
def __init__(self,name,breed,aggressivity,life_value):
super().__init__(name, aggressivity, life_value) #执行父类Animal的init方法
self.breed = breed #派生出了新的属性
def bite(self, people):
'''
派生出了新的技能:狗有咬人的技能
:param people:
'''
people.life_value -= self.aggressivity
def eat(self):
# Animal.eat(self)
#super().eat()
print('from Dog')
class Person(Animal):
'''
人类,继承Animal
'''
def __init__(self,name,aggressivity, life_value,money):
#Animal.__init__(self, name, aggressivity, life_value)
#super(Person, self).__init__(name, aggressivity, life_value)
super().__init__(name,aggressivity, life_value) #执行父类的init方法
self.money = money #派生出了新的属性
def attack(self, dog):
'''
派生出了新的技能:人有攻击的技能
:param dog:
'''
dog.life_value -= self.aggressivity
def eat(self):
#super().eat()
Animal.eat(self)
print('from Person')
egg = Person('egon',10,1000,600)
ha2 = Dog('二愣子','哈士奇',10,1000)
print(egg.name)
print(ha2.name)
egg.eat()
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师
抽象类
什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
抽象类与接口类
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念。
1.多继承问题
在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。
2.方法的实现
在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
钻石继承
继承顺序

继承原理
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
>>> F.mro() #等同于F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
多态:
在python中,传参之间并没有数据类型限制,所以python默认多态.
封装:
把一些属性和方法放在一个类里,这本身就是一种封装.
【封装】
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
【好处】
1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性;
【封装原则】
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
class Goods:
__discount = 0.8 # 私有静态属性
def __init__(self, name, price):
self.__name = name
self.__price = price
@property # 把一个方法伪装成属性
def name(self):
return self.__name
@name.setter # 修改伪装后的属性
def name(self, new_name):
self.__name = new_name
@name.deleter # 删除属性
def name(self):
del self.__name
@property
def price(self):
return self.__price * Goods.__discount
@price.setter
def price(self, new_price):
if type(new_price) is int:
self.__price = new_price
apple = Goods('苹果', 10)
del apple.name
print(apple.name)
# 定义一个类 # 类里面的方法 # 并没有用到self class Goods: __discount = 0.8 @classmethod # 类方法 def change_discount(cls, new_discount): cls.__discount = new_discount @classmethod def get_discount(cls): return cls.__discount # apple = Goods() Goods.change_discount(0.75) print(Goods.get_discount()) # 类方法 # 调用:不需要实例化 直接用类名调用就好 # 定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类 # 什么时候用类方法? # 需要使用静态变量 且 不需要和对象相关的任何操作的时候 # 静态方法 # 如果这个方法 既不需要操作静态变量 # 也不需要使用对象相关的操作, # 就使用静态方法 class A: @staticmethod def func(name): # 静态方法 print(123) A.func('alex') # 面向对象编程:专门为面向对象编程提供的一个方法——staticmethod # 它完全可以当做普通函数去用,只不过这个函数要通过类名.函数名调用 # 其他 传参 返回值 完全没有区别 # 类里面,一共可以定义这三种方法: # 普通方法 self # 类方法 cls # 静态方法

浙公网安备 33010602011771号