面向对象初识二
面向对象三大特性之继承
一、什么是继承:
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
python中类的继承分为:单继承和多继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class ChildClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是hildClass pass class ChildClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
在python3中 所有的类都继承自object
class ParentClass1: pass print(ParentClass1.__bases__) >>> (<class 'object'>,)
class ParentClass1: pass class ParentClass2: pass class ChildClass1(ParentClass1): # 单继承 pass class ChildClass2(ParentClass1,ParentClass2): # 多继承 pass print(ChildClass1.__base__) # 会显示该类的一个父类 print(ChildClass2.__base__) # 会显示该类的第一个父类 print(ChildClass2.__bases__) # 会显示该类的所有父类 >>> <class '__main__.ParentClass1'> <class '__main__.ParentClass1'> (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
二、继承与抽象(先抽象再继承)
抽象即抽取类似或者说比较像的部分。
抽象分成两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
三、继承与重用性
# 猫类 : 吃eat 喝drink 睡sleep 爬树climb # 狗类 : 吃eat 喝drink 睡sleep 看家watch class Pet: def __init__(self,name,kind,food): self.name = name # 派生属性 self.kind = kind self.food = food def eat(self): print('%s吃%s'%(self.name,self.food)) def drink(self): print('%s在喝水'%self.name) def sleep(self): print('%s在睡觉' % self.name) class Cat(Pet): def climb(self): # 派生方法 print('%s在爬树' % self.name) class Dog(Pet): def watch(self): # 派生方法 print('%s在看家' % self.name) tom = Cat('Tom','暹罗猫','猫粮') # 子类使用名字(方法和静态变量),如果在子类中没有,就使用父类的\ # Cat('Tom','暹罗猫','猫粮') 实例化 hei = Dog('小黑','2哈','狗粮') tom.eat() hei.eat() tom.climb() hei.watch()
实例化一个类进行了两步:
1、 创建一个空对象
2、执行__init__方法:子类没有用父类的
子类使用名字(方法和静态变量),如果在子类中没有,就使用父类的
在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时
我们不可能从头开始写一个类B,这就用到了类的继承的概念。
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Animal: # 动物 def __init__(self,name,aggr,hp): #方法 动态属性 内置的双下方法 self.name = name # 对象属性 实例属性 self.aggr = aggr self.hp = hp class Person(Animal): # 类名 Person def __init__(self,name,sex,aggr,hp): self.sex = sex # 派生属性 Animal.__init__(self,name,aggr,hp) super().__init__(name,aggr,hp) def attack(self,dog): # 自定义方法 print('%s打了%s'%(self.name,dog.name)) dog.hp -= self.aggr class Dog(Animal): def __init__(self,name,kind,aggr,hp): self.kind = kind # 派生属性 Animal.__init__(self,name,aggr,hp) def bite(self,person): print('%s咬了%s'%(self.name,person.name)) person.hp -= self.aggr alex = Person('alex','不详',1,250) hei = Dog('小黑','teddy',260,10000) alex.attack(hei) hei.bite(alex)
四、组合与继承
软件重用的重要方式 有两种一种是组合,另一种是继承
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
组合和继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同
1、继承的方式
通过继承建立了派生类(子类)与基类(父类)之间的关系,它是一种“是”的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师
2、组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种“有”的关系,比如教授有生日,教授教Python课程
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
五、派生
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
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))
注意:像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
super用法:
在python3中,子类执行父类的方法也可以直接用super方法.
super是用于派生类当中的,就是我们在子类中需要调用父类的函数,并在其基础上进行修改
使用范围仅限于新式类中,在Python2中,super()中需要两个参数,Python3中不需要
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: def hahaha(self): print('A') class B(A): def hahaha(self): super().hahaha() #super(B,self).hahaha() #A.hahaha(self) print('B') a = A() b = B() b.hahaha() super(B,b).hahaha()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# super class Animal: # 动物 def __init__(self,name,aggr,hp): #方法 动态属性 内置的双下方法 self.name = name # 对象属性 实例属性 self.aggr = aggr self.hp = hp def eat(self): print('in Animal eat') class Person(Animal): # 类名 Person def __init__(self,name,sex,aggr,hp): self.sex = sex # 派生属性 # Animal.__init__(self,name,aggr,hp) super().__init__(name,aggr,hp) # 单继承中 super会寻找父类 # 且在使用super调用父类方法的时候不需要再传self参数 def eat(self): print('in Person eat') # Animal.eat(self) # super().eat() alex = Person('alex','不详',1,250) print(alex.__dict__) Animal.eat(alex) super(Person,alex).eat()
# #coding:utf-8 # #super在Python2中的用法: # #1.super(自己的类,self).父类的函数名字 # #2.super只能用于新式类 # class People(object): # def __init__(self,name,sex,age): # self.name = name # self.age = age # self.sex = sex # def walk(self): # print("%s is walking"%self.name) # class Chinese(People): # country = "China" # def __init__(self,name,sex,age,language="Chinese"): # # self.name = name # # self.sex = sex # # self.age = age # #People.__init__(self,name,sex,age) # super(Chinese,self).__init__(name,sex,age) # self.language = language # c = Chinese("egon","male",18) # print (c.name,c.age,c.language) # #在Python3中 # class People: # def __init__(self,name,sex,age): # self.name = name # self.sex = sex # self.age = age # def walk(self): # print("%s is walking"%self.name) # class Chinese(People): # country = "China" # def __init__(self,name,sex,age,language="Chinese"): # super().__init__(name,sex,age) # self.language = language # def walk(self,x): # super().walk()#walk后面不需要加参数 # print("子类的x",x) # c = Chinese("egon","male",18) # # print(c.name,c.age,c.sex) # c.walk(1)
当我们使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: def __init__(self): print('A的构造方法') class B(A): def __init__(self): print('B的构造方法') super().__init__() class C(A): def __init__(self): print('C的构造方法') super().__init__() class D(B, C): def __init__(self): print('D的构造方法') super().__init__() f1 = D() print(D.__mro__)
面向对象特性之多态
一、抽象类与接口类
接口类:
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
>>>> 在Python里面 没有接口类的概念
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
接口类 : 接口类就是一个规范 接口类一般是项目设计人员写好的
1.多继承问题
在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。
2.方法的实现
在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
java里 from abc import ABCMeta,abstractmethod # 接口类 : 接口类就是一个规范 接口类一般是项目设计人员写好的 class Payment(metaclass=ABCMeta): #规范 @abstractmethod def pay(self,money): ''' :param money: :return: ''' raise NotImplementedError # 微信支付 class WeChatPay(Payment): def pay(self,money): print('通过微信支付了%s元钱'%(money)) # 支付宝支付 class AliPay(Payment): def pay(self,money): print('通过支付宝支付了%s元钱'%(money)) # apple pay class ApplePay(Payment): pass def pay(self,money): print('通过支付宝支付了%s元钱' % (money)) wp = WeChatPay() alp = AliPay() app = ApplePay() def pay(pay_obj,money): # 程序的归一化设计 pay_obj.pay(money) pay(alp,100) pay(wp,100) pay(app,100)
接口类是一个规范
多种支付方式,每一种支付方式都是一个类,
每一个类中定义一个支付方法完成支付功能
由于每一种支付方式在程序中表现出来的就是支付类的对象
拿到每一个支付对象都需要调用支付方法
为了方便支付方法的调用
需要统一一个入口 pay函数
在Java里有Interface语法:
在python里没有接口类这种数据类型,没有接口类专门的语法
但是可以通过继承abc模块实现接口的功能
### 接口类不能被实例化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from abc import ABCMeta,abstractmethod class FlyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self): print(11111) class SwimAnimal(metaclass=ABCMeta): @abstractmethod def swim(self): pass class WalkAnimal(metaclass=ABCMeta): @abstractmethod def walk(self): pass class Swan(SwimAnimal,WalkAnimal,FlyAnimal): # 飞 def fly(self):pass # 游泳 def swim(self):pass # 走 def walk(self):pass class Qq(SwimAnimal,WalkAnimal): def swim(self):pass # 走 def walk(self):pass class Bird(FlyAnimal,WalkAnimal): # 飞 def fly(self):pass # 走 def walk(self):pass Swan()
二、抽象类
抽象类 规范一个类的类
什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from abc import ABCMeta , abstractmethod class File(metaclass=ABCMeta): @abstractmethod def read(self): f = open('file','r') self.f = f @abstractmethod def write(self): f = open('file','w') class Word(File): def read(self): # 打开一个文件 # 读文件 # 关闭一个文件 super().read() self.f.read() self.f.close() class Excle(File): def read(self): # 打开一个文件 # 读某一列 读某一列 # 关闭一个文件 super().read() self.f.readline() self.f.close() class PPT(File): def read(self): # 打开一个文件 # 读文字 读表格 读图片 # 关闭一个文件 super().read() self.f.readpicture() self.f.close()
在python里 抽象类和接口类 没区别
在java里 有区别
java的接口规定里面的方法一定不能实现(一句代码也不能写)
抽象类 单继承
无论接口类 还是抽象类 其实都是一种面向对象编程的开发规范,只是在接口类或者抽象类中 去约束继承它的子类必须实现某些方法
对于java代码来说:
如果发生多继承 那么一定是接口类 且里面的方法都不能实现,如果在方法里有了实现 那么一定是单继承 的抽象类
但是对于python来说:
就没有这些约束因为python没有接口的概念对于类的继承 没有多继承的限制
实际上abc模块是帮我实现抽象类的方法,只是我们用它来模仿接口类的效果了
在python中,只要metaclass = ABCMeta 定义了抽象方法(@abctractmethod)
这个类就不能被实例化,你可以说他是一个抽象类。
多态
多态指的是一类事物有多种形态,如动物有多种形态:人,狗,猪
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao')
文件有多种形态:文本文件,可执行文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import abc class File(metaclass=abc.ABCMeta): #同一类事物:文件 @abc.abstractmethod def click(self): pass class Text(File): #文件的形态之一:文本文件 def click(self): print('open file') class ExeFile(File): #文件的形态之二:可执行文件 def click(self): print('execute file')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1+'1' 强类型 def func(name,age):pass # 弱类型 func('alex',18) func(18,'alex') class WeChatPay: def pay(self,money): print('通过微信支付了%s元钱'%(money)) class AliPay: def pay(self,money): print('通过支付宝支付了%s元钱'%(money)) def pay(pay_obj,money): # 程序的归一化设计 pay_obj.pay(money) w = WeChatPay() a = AliPay() pay(w,100)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
python当中对相似的类的实现方式 class List: def index(self): pass def slice(self): pass def len(self): pass def append(self): pass class Tuple: def index(self): pass def slice(self): pass def len(self): pass class Str: def index(self): pass def slice(self): pass def len(self): pass def split(self): pass l = List() t = Tuple() s = Str() l.len() # 方法 def len(obj): return obj.len()
如果建立规范 那么必须通过继承抽象类的形式强制约束
鸭子类型:
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 多态 class List(序列): def index(self): pass def slice(self): pass def length(self): pass def append(self): pass class Tuple(序列): def index(self): pass def slice(self): pass def len(self): pass class Str(序列): def index(self): pass def slice(self): pass def len(self): pass def split(self): pass l = List() t = Tuple() l.len() # 方法 # def len(序列 obj): # return obj.len()
六、钻石继承
继承顺序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: def wahaha(self):print('in A') class B(A): def wahaha(self):print('in B') class C(B): def wahaha(self):print('in C') class D(C):pass # def wahaha(self):print('in D') d = D() d.wahaha()
不要发生循环继承
依赖倒置原则 :
高层模块不应该依赖低层模块
python3中统一都是新式类
pyhon2中才分新式类与经典类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类
继承原理
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.如果对下一个类存在两个合法的选择,选择第一个父类
继承总结
1、继承的作用
继承的作用
减少代码的重用 提高代码可读性 规范编程模式
几个名词
抽象:抽象即抽取类似或者说比较像的部分。是一个从具题到抽象的过程。 继承:子类继承了父类的方法和属性 派生:子类在父类方法和属性的基础上产生了新的方法和属性
抽象类与接口类
1.多继承问题 在继承抽象类的过程中,我们应该尽量避免多继承; 而在继承接口的时候,我们反而鼓励你来多继承接口 2.方法的实现 在抽象类中,我们可以对一些抽象方法做出基础实现; 而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
钻石继承
新式类:广度优先 经典类:深度优先
面向对象三大特性封装
【封装】
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
【好处】
1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性;
【封装原则】
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
广义上的封装 : 属于一个类的静态和动态属性 总是出现在一个类中,使用时永远用类名或者对象名调用
狭义上的封装 : 就是把变量 \ 方法私有化,在类的外部以及子类中不能直接使用了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: STATIC = 'aaa' # 静态变量 __S = 'bbb' # 私有的静态变量 def wahaha(self): print(A.__S) # _A__S print(A.STATIC) print(A.__dict__) print(A._A__S) # 在类的外面调用私有的变量 a = A() a.wahaha() A.__B = 'ccc' # 在类的外部添加了一个静态变量 print(A.__dict__) # 我们不能在一个类的外部创建一个"私有的"变量 print(A.__B)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class B: def __init__(self,name,pwd): self.name = name self.__pwd = pwd # 也可以创建对象的私有属性 def qqxing(self): self.__a = 'A' # _B__a def get_pwd(self): print(self.__pwd) b = B('alex','alex3714') b.qqxing() print(b.name) print(b._B__pwd) # 当在类外部的时候,我们也不能直接使用对象的私有属性 b.get_pwd()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class C: def __ppt(self): # 私有的方法 print('ppt') self.age = 83 def open(self): self.__ppt() print('打开文件') c = C() c._C__ppt() # 不能直接调用 c.open() c.name = 'alex' >>>> ppt ppt 打开文件
私有的静态变量、 对象属性 方法
私有的 只能在类的内部定义和使用,__私有名字
在类外部使用私有静态变量 _类名__私有的名字
私有的名字 不能被子类继承
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Room: def __init__(self,owner,price,length,width,height): self.owner = owner self.__price_single = price #单价 self.__length = length self.__width = width self.height = height def get_area(self): return self.__length * self.__width def get_price(self): return self.__price_single * self.get_area() alex = Room('alex',1000000,2,1,0.8) print(alex.get_area()) print(alex.get_price())
内置函数:property、classmethod、staticmethod
property:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Person: def __init__(self,name,height,weight): self.name = name self.__height = height self.__weight = weight @property #将一个方法伪装成属性 def bmi(self): return self.__weight / (self.__height**2) wang = Person('王子',1.77,69) print(wang.bmi)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
圆形类 : r 面积area 周长perimeter from math import pi class Circle: def __init__(self,r): self.r = r @property def area(self): return self.r*self.r*pi @property def perimeter(self): return 2*pi*self.r c = Circle(10) print(c.area) print(c.perimeter)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: def __init__(self,name): self.__name = name @property def name(self): return self.__name @name.setter def name(self,new_name): if type(new_name) == str: self.__name = new_name alex = Foo('alex') print(alex.name) alex.name = 123 # 为了迎合属性的设置方式 print(alex.name)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: def __init__(self,name): self.__name = name @property def name(self): return self.__name @name.setter def name(self,new_name): if type(new_name) == str: self.__name = new_name @name.deleter def name(self): del self.__name alex = Foo('alex') del alex.name print(alex.name)
商品 价格 原价 打折 = 折后价 class Goods: def __init__(self,name,price,discount): self.name = name self.__price = price self.discount = discount @property def price(self): return self.__price * self.discount apple = Goods('apple',5,0.8) print(apple.price)
为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,
这种特性的使用方式遵循了统一访问的原则
ps:面向对象的封装有三种方式:
public :
这种其实就是不封装,是对外公开的
protected:
这种封装方式对外不公开,但对朋友(friend)或者子类公开
private :
这种封装对谁都不公开
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,
然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现
一个静态属性property本质就是实现了get,set,delete三种方法
classmethod:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Goods: __discount = 0.8 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price*Goods.__discount @classmethod #讲一个普通方法装饰为一个类方法 def change_discount(cls,new_dis): # 类方法 cls.__discount = new_dis Goods.change_discount(1) cig = Goods('cigrette',20) print(cig.price) cig.change_discount(0.2) print(cig.price) cig.change_discount(1) print(cig.price) >>20 >>4 >>20
类方法是被@classmethod装饰的特殊方法,被装饰之后,方法默认接收一个 类 作为参数
之后所有的操作都只能和 类中的静态变量相关 而不应该和对象相关
类名 和 对象名 都可以直接调用类方法
staticmethod:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Student: def __init__(self,name): self.name = name @staticmethod #装饰一个不需要self参数 也不需要cls参数的函数 def login(a,b,c): # 普通的函数 usr = input('username>>>') pwd = input('password>>>') if usr == 'alex' and pwd == '123': obj = Student(usr) return obj # 学生 login # 用户名 密码 属性 ret = Student.login(1,2,3) print(ret) >>> username>>>alex password>>>123 <__main__.Student object at 0x000000000287FD30>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: def func(self): print('in father') class Son(Foo): def func(self): print('in son') s = Son() s.func() # 请说出上面一段代码的输出并解释原因?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: __role = 'CHINA' @classmethod def show_role(cls): print(cls.__role) @staticmethod def get_role(): return A.__role @property def role(self): return self.__role a = A() print(a.role) print(a.get_role()) a.show_role() # __role在类中有哪些身份? # 以上代码分别输出哪些内容? # 这三个装饰器分别起了什么作用?有哪些区别? >>> CHINA CHINA CHINA