Python基础
- Python基础-PEP8: Python代码风格指南
- Python基础-面向对象(四)
- Python基础-面向对象(三)
- Python基础-面向对象(二)
- Python基础-面向对象(一)
- Python基础-模块
- Python基础-异常的捕获和处理
- Python基础-文件夹的操作
- Python基础-文件的操作
- Python基础-函数(三)
- Python基础-函数(二)
- Python基础-函数(一)
- Python基础-字符串,元组,列表,字典,集合之间的相互转
- Python基础-字符串,元组,数组,字典-公共方法
- Python基础-集合set
- Python基础-字典
- Python基础-元组
- Python基础-列表
- Python基础-字符串
- Python基础-break和continue
- Python基础-for循环
- Python基础-while循环
- Python基础-if判断语句
- Python基础-数据类型转换,ASCII码对照表
- Python基础-运算符
- Python基础-输出print和输入input
- Python基础-标识符和关键字
- Python基础-变量以及类型
- Python基础-注释的引入
- Python基础-第一个python程序
- Python基础-简介
Python基础-面向对象(四)
Python基础-面向对象(四)
私有权限
面向对象三大特性:封装、继承、多态
封装的意义
1,将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;
2,隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;
3,对类的属性和方法增加 访问权限控制。
私有权限:在属性名和方法名 前面 加上两个下划线 __
1,类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问;
2,类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问;
3,私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。
剧情发展: 大猫觉得配方传承下去没问题,但是钱是辛辛苦苦挣得血汗钱,不想传给徒弟。(私有权限)
# 定义一个Master父类 class Master(object): def __init__(self): # 属性 self.gufa = '古法煎饼果子配方' # 方法 def make_cake(self): print('按照%s制作古法煎饼果子' % self.gufa) def eat_master(self): print('在师傅家吃饭') # 定义一个School父类 class School(object): def __init__(self): self.gufa = '现代煎饼果子配方' def make_cake(self): print('按照%s制作现代煎饼果子' % self.gufa) def eat_school(self): print('在学校吃饭') # 定义一个Prentice子类,继承父类Master,School class Prentice(Master, School): # 子类重写了属性和方法 def __init__(self): self.gufa = '猫式煎饼果子配方' self.__money = 1000 # 亿美金 def make_cake(self): print('用%s配方制作煎饼果子' % self.gufa) # 获取Master的属性和方法 def make_master_cake(self): Master.__init__(self) Master.make_cake(self) # 获取School 的属性和方法 def make_school_cake(self): School.__init__(self) School.make_cake(self) # 新建一个大猫徒弟的类,继承大猫类Prentice class PrenticePrentice(Prentice): pass # 创建大猫徒弟的实例对象 pp = PrenticePrentice() pp.make_cake() # 用猫式煎饼果子配方配方制作煎饼果子 print(pp.gufa) # 猫式煎饼果子配方 pp.make_master_cake() # 按照古法煎饼果子配方制作古法煎饼果子 print(pp.gufa) # 古法煎饼果子配方 pp.make_school_cake() # 按照现代煎饼果子配方制作现代煎饼果子 print(pp.gufa) # 现代煎饼果子配方 #monye式私有属性,实例化继承不了 print(pp.__money) # 继承大猫的钱,出错:AttributeError: 'PrenticePrentice' object has no attribute '__money'
Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线'__',则表明该属性和方法是私有权限,否则为公有权限。
修改私有属性的值
如果需要修改一个对象的属性值,通常有2种方法:
1,对象名.属性名 = 数据 ----> 直接修改
2,对象名.方法名() ----> 间接修改
私有属性不能直接访问,所以无法通过第一种方式修改,一般的通过第二种方式修改私有属性的值:定义一个可以调用的公有方法,在这个公有方法内访问修改。
# 定义一个Master父类 class Master(object): def __init__(self): # 属性 self.gufa = '古法煎饼果子配方' # 方法 def make_cake(self): print('按照%s制作古法煎饼果子' % self.gufa) def eat_master(self): print('在师傅家吃饭') # 定义一个School父类 class School(object): def __init__(self): self.gufa = '现代煎饼果子配方' def make_cake(self): print('按照%s制作现代煎饼果子' % self.gufa) def eat_school(self): print('在学校吃饭') # 定义一个Prentice子类,继承父类Master,School class Prentice(Master, School): # 子类重写了属性和方法 def __init__(self): self.gufa = '猫式煎饼果子配方' self.__money = 1000 # 亿美金 # 返回私有属性的值 def get_money(self): return self.__money def set_money(self,num): self.__money = num return num def make_cake(self): print('用%s配方制作煎饼果子' % self.gufa) # 获取Master的属性和方法 def make_master_cake(self): Master.__init__(self) Master.make_cake(self) # 获取School 的属性和方法 def make_school_cake(self): School.__init__(self) School.make_cake(self) # 新建一个大猫徒弟的类,继承大猫类Prentice class PrenticePrentice(Prentice): pass # 创建大猫徒弟的实例对象 pp = PrenticePrentice() print(pp.get_money()) # 可以通过访问公有方法set_money()来获取私有属性的值 pp.set_money(2000) # 可以通过访问公有方法get_money()来修改私有属性的值 print(pp.get_money())
多态
大家应该听说过这样的故事:有一个中医世家,父亲是当地一位非常有名的老大夫,看病看的非常好,儿子从小就跟着父亲学医,医术也不错. 突然县太爷家的千金生了重病,急需老大夫前去治病,但是老大夫又不在家,就请了老大夫的儿子前去给治病. 最后儿子也把病给治好了
那么,在python语言中能不能做类似的事情,比如说 在需要调用父类对象方法的地方,我们也可以调用子类对象的方法呢?
当然可以! 要想这样,我们需要使用接下来要学习的知识点:多态.
好,下面我们就开始正式讲解 多态.在讲解的时候:
1.先讲解"多态"的概念
2.再讲解如何使用多态
3.最后讲解多态的好处
什么是多态?
在需要使用父类对象的地方,也可以使用子类对象, 这种情况就叫多态.
比如, 在函数中,我需要调用 某一个父类对象的方法, 那么我们也可以在这个地方调用子类对象的方法.
如何在程序中使用多态?
可以按照以下几个步骤来写代码:
1.子类继承父类
2.子类重写父类中的方法
3.通过对象调用这个方法
class Father(object): def cure(self): print('父亲给人治病') class Son(Father): # 重新cure方法 def cure(self): print('儿子给人治病') # 义函数,在里面 调用医生的cure函数 def call_cure(doctor): # 调用医生治病的方法 doctor.cure() # 创建父类对象 father = Father() # 调用函数,把父类对象传递函数 call_cure(father) # 创建子类对象 son = Son() # 调用函数,把子类对象传递函数 call_cure(son)
使用多态的好处
多态的好处:给call_cure(doctor)函数传递哪个对象,在它里面就会调用哪个对象的cure()方法,也就是说在它里面既可以调用son对象的cure()方法,也能调用father对象的cure()方法,当然了也可以在它里面调用Father类其它子类对象的cure()方法,这样可以让call_cure(doctor)函数变得更加灵活,额外增加了它的功能,提高了它的扩展性.
类属性和实例属性
在了解了类基本的东西之后,下面看一下python中这几个概念的区别。
先来谈一下类属性和实例属性:
在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问
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)
总结:如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
类方法
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。
class People(object): country = 'china' #类方法,用classmethod来进行修饰 @classmethod def get_country(cls): return cls.country p = People() print(p.get_country()) #可以用过实例对象引用 print(People.get_country()) #可以通过类对象引用
类方法还有一个用途就是可以对类属性进行修改:
class People(object): country = 'china' #类方法,用classmethod来进行修饰 @classmethod def get_country(cls): return cls.country @classmethod def set_country(cls,country): cls.country = country p = People() print(p.get_country()) # china 可以用过实例对象访问 print(People.get_country()) # china 可以通过类访问 p.set_country('japan') print(p.get_country()) # japan print(People.get_country()) # japan
结果显示在用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变
静态方法
需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数,可以通过对象和类来访问。
class People(object): country = 'china' @staticmethod #静态方法 def get_country(): return People.country p = People() # 通过对象访问静态方法 print(p.get_country()) # china # 通过类访问静态方法 print(People.get_country()) # china
总结:
从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;
实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类实例对象来引用
最后修改:2020年3月2日 22:03