敲黑板,面向对象的三大特征:python
封装、继承和多态。函数
封装就是隐藏底层的实现细节,只提供公有的接口供外界访问, 这样当底层实现细节改变的时候,就不会对外界形成影响。ui
在类的设计角度,咱们能够将属性或方法(类的成员)定义为私有,来实现封装。设计
私有成员只能在定义类的内部进行访问,在类外是没法进行访问的。3d
私有成员的定义方式:以_进行开头,可是不能以两个或多个进行结尾。code
class Computer: def __init__(self,cpu): self.cpu = cpu # 私有属性(私有的实例属性) self.__memory = 1024 # 在定义私有属性“类的内部”,能够访问私有成员 #print(self.__memory) c = Computer("某cpu") c.__memory # 能够发现私有属性不可以在外部直接访问
结果以下:对象
class Computer: def __init__(self,cpu): self.cpu = cpu # 私有属性(私有的实例属性) self.__memory = 1024 # 在定义私有属性“类的内部”,能够访问私有成员 print(self.__memory) def x(self): pass # 若是想要采用公有的方法(在类的外部),访问私有属性。须要额外定义两个方法 def set_memory(self,memory): self.__memory = memory def get_memory(self): return self.__memory c = Computer("某cpu") c.get_memory()
结果以下:blog
为何非要定义为:私有属性呢?定义为通常的实例属性不是也能够吗?继承
缘由在于:定义为私有属性后。当咱们之后须要对类中某属性作出修改时,只须要在内部修改,而不会对外部的使用者,产生影响。接口
假如不将memory定义为私有属性
class Computer: def __init__(self, cpu): self.cpu = cpu self.memory = 1024 c = Computer("某cpu") print(c.memory) # 1024 c.memory = 6666 print(c.memory) # 6666
假如说,因为某种业务要求,须要将memory改成memory2,那么,咱们不只须要在内部进行修改。同时外部调用者也须要进行修改。假如你有不少粉丝使用这个,估计都会骂你(假如代码中有不少行都须要将memory改成memory2)
其实,私有属性也并不是真正的私有。只是将名称进行了一下假装而已。
假装成了:类名_私有属性的名称
这就意味着,在类的外部,咱们能够经过真实名称对私有属性进行访问。
可是,不建议这么作。假装就是为了保证封装性,而你非要去捅破。
class Computer: def __init__(self,cpu): self.cpu = cpu self.__memory = 1024 c = Computer("某cpu") c.__memory c._Computer__memory # 切记不要这么作。这样作破坏了封装性
结果以下:
class PythonTeacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"个人名字是{self.name},所在小组是{self.group}") def teach(self): print("打开pycharm") print("输入代码") print("知识点讲解") class JaVaTeacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"个人名字是{self.name},所在小组是{self.group}") def teach(self): print("打开eslipse") print("输入代码") print("知识点讲解")
继承体现的是通常与特殊的关系。若是两个类A与B,A(苹果)是一种特殊的B(水果),则咱们就称A继承了B,A就是子类,B就是父类。
子类一旦继承了父类,子类就会成为一种特殊的父类,子类就会具有父类的一切特征。所以,父类可以作的事情,子类也能够作到。
子类继承了父类,子类就会继承父类中定义的成员,就好象子类中本身定义了同样。
class Fruit: def show(self): print("水果") # 继承,在定义类时,给出继承的父类 class Apple(Fruit): pass f = Fruit() f.show() a = Apple() a.show()
结果以下:
定义类时,若没有显示的继承任何类,则代表继承object类,object是python中最根层次的类。
咱们能够将公共的功能提取出来,放入父类中。而后使用每个子类去继承父类。这样,就无需将这些公共的功能分别放在子类中实现。从而避免了代码的重复性。
子类继承父类,子类能够吸取“父类的功能”,此外,子类还能够增长本身特有的功能。若是父类的功能对于子类来讲不适用,子类就能够改造(重写)父类中的功能。
class Bird: def fly(self): print("鸟飞") def describe(self): print("有羽毛,无牙齿,蛋生") class Ostrich(Bird): # 父类中的fly功能,不适合鸵鸟。所以,子类须要对父类的功能进行修改 def fly(self): print("不会飞") # 子类增长本身特有的功能 def run(self): print("高速奔跑") c = Ostrich() c.fly(),c.describe(),c.run()
结果以下:
子类能够继承父类中定义的:类属性、实例属性;类方法、实例方法;静态方法。
class Father: class_attr = 1 def __init__(self): self.instance_attr = 2 def instance_method(self): pass @classmethod def class_method(cls): pass @staticmethod def static_method(): pass class Son(Father): pass s = Son()
而后子类就能够调用父类的类属性、实例属性;类方法、实例方法;静态方法。
对于父类中的实例属性,咱们须要留意。若是子类中定义了本身的init方法,则不会调用父类的init方法。所以,父类方法中绑定的实例属性,就不会绑定到子类对象上,也就是说父类的实力属性,子类不会获得继承。
class Father: class_attr = 1 def __init__(self): self.instance_attr = 2 def instance_method(self): pass @classmethod def class_method(cls): pass @staticmethod def static_method(): pass class Son(Father): def __init__(self): pass so = Son() so.instance_attr
结果以下:
有时候,父类的初始化,可能"并不彻底适合于"子类。这是,子类须要定义本身的init方法。
"并不彻底适合于"指的是:父类中,有的实例属性适合雨子类,有的不适合于子类。子类中既要定义本身的init方法,又想使用父类中部分实例属性,那么该怎么作呢?
class Person(): delf __init__(self,name,age): self.name = name self.age = age class Student(Person): delf __init__(self,name,age,id): self.name = name self.age = age self.id = id # 父类的初始化不彻底适合于子类,可是,也没有彻底不适合于子类
整改:在子类的init方法中,去调用父类的init方法,这样能够"避免代码重复"。
class Person(): def __init__(self,name,age): self.name = name self.age = age class Student(Person): def __init__(self,name,age,id): # 调用父类的__init__方法 super().__init__(name,age) # 调用父类的__init__方法 self.id = id s = Student("梁某人",18,2017011) s.name,s.age,s.id
结果以下:
实际上,私有属性也是能够被子类继承的。只不过,子类继承的不是私有属性原本的名字,而是私有属性假装后的名字。
虽然子类能够继承并访问父类的私有属性,可是不建议这么作。既然是私有的,确定是不肯意咱们去访问的。
class Father: def __m(self): print("私有方法") class Son(Father): def p(self): # 经过假装以后的名字,进行访问 self._Father__m() s = Son() s.p()
结果以下:
① isinstance(参数一,参数二)
class Father: pass class Son(Father): pass f = Father() s = Son()
来检测一下:
② issubclass()
class Father: pass class Son(Father): pass f = Father() s = Son()
再来检测一下:
当父类中的成员,对子类不彻底适用时,子类就能够从新定义该成员。
class Bird: def fly(self): print("鸟飞") class Ostrich(Bird): # 父类中的fly功能,不适合鸵鸟。所以,子类须要对父类的功能进行修改 def fly(self): print("不会飞") # 子类增长本身特有的功能 def run(self): print("高速奔跑") o = Ostrich() o.fly()
结果以下:
class Bird: def fly(self): print("鸟飞") class Ostrich(Bird): # 父类中的fly功能,不适合鸵鸟。所以,子类须要对父类的功能进行修改 def fly(self): # 经过super()方法,能够实现对父类中同名方法的访问 super().fly() # super()既能够调用父类中的私有属性。也能够调用父类中的方法 print("不会飞") o = Ostrich() o.fly()
结果以下:
python中,一个子类能够继承多个父类。多个父类的成员,均可以被子类所继承。继承多个父类使用 , 分割。
class Rectangle: def area(self): print("矩形求面积") class Diamond: def area(self): print("菱形求面积") class Square(Rectangle,Diamond): #老是按照这里的前后顺序,一一继承 def t(self): self.area() s = Square() s.t()
结果以下:
class Rectangle: def area(self): print("矩形求面积") class Diamond: def area(self): print("菱形求面积") class Square(Diamond,Rectangle): #老是按照这里的前后顺序,一一继承 def t(self): self.area() s = Square() s.t()
结果以下:
多继承:按照继承原则,每一个父类看做一个分支。按照顺序进行查找,深度优先。可是有一个原则:子类必定会在父类以前被搜索。
class Teacher: def __init__(self,name,group): self.name = name self.group = group def introcude(self): print(f"个人名字是{self.name},所在小组是{self.group}") def teach(self): print("输入代码") print("知识点讲解") class PythonTeacher(Teacher): def __init__(self,name,group): super().__init__(name,group) def teach(self): print("打开pycharm") super().teach() class JaVaTeacher(Teacher): def __init__(self,name,group): super().__init__(name,group) def teach(self): print("打开eslipse") super().teach() p = PythonTeacher("梁某人", 10) print(p.introcude(), p.teach())
结果以下:
j = JaVaTeacher("梁三",666) print(j.group,j.teach())
结果以下:
这个在python中基本体现不出来,知道面向对象有多态这个特性就好了。