继承的简介
1、提高代码复用性
2、让类与类之间产生了关系,有了这个关系,才有了多态
3、继承也是面向对象的三大特征之一
换句话说:没有继承哪里来的多态。
注意:在定义类时后面加上括号,括号内中指定的是当前类的父类(超类、基类、super)
在创建类的时候,如果省略了父类,那么Python会自动添加一个类(object)类 。所有类都继承object,object是所有类的父类
#创建一个类
class Person():
#创建一个方法:
def sleep(self):
print('我在睡觉')
#在创建一个方法
def run(self):
print('我在跑步')
#创建一个类,并继承他的类
class student(Person): #定义一个类让他继承他的父类(在定义类时,可以在类括号加上括号,括号中的内容指定的类是当前类的父类)
pass
#创建一个实例对象
p1 = student()
p1.run()
p1.sleep()
运行结果:
我在跑步
我在睡觉
isinstance检查一个类是否是另一个类的实例
issubclass检查一个类是否是另一个类的子类
#检查一个类是否是另一个类的实例
result = isinstance(p1,student)
result1 = isinstance(p1,Person)
print(result)
print(result1)
#检查一个类是否是另一个类的子类
result3 = issubclass(student,Person)
print(result3)
result4 = issubclass(Person,object)
print(result4)
运行结果:
True
True
True
True
方法重写
当子类中存在与父类重名的方法,通过子类的实例来调用方法时,会调用子类的方法而不是父类的方法,这个特点称之为方法的重写(覆盖 override)
#创建一个类
class Person(object): #不写object也可以,会自动继承object方法
#创建一个方法
def speak(self):
print('这个是Person的方法')
#创建第二个方法
def run(self):
print('这个是Person在跑')
#创建第二个类,并继承Person类
class teacher(Person):
#创建一个teacher方法
def speak(self):
print('这个是teacher的方法')
p1 = teacher()
p1.speak()
p1.run()
运行结果:
这个是teacher的方法
这个是Person在跑
方法重写:(会优先去当前对象中寻找方法,如果有直接调用该方法。如果没有,则去当前定义的父类中寻找,如果有将直接调用。如果没有,则会去父类的父类中寻找,以此类推直到找到object为止,如果有则调用,没有则报错)
class A(object):
def speak(self):
print('a方法')
class B(A):
def speak(self):
print('B方法')
class C(B):
pass
p = C()
p.speak()
运行结果:
B方法
父类中的方法都会被子类继承,包括特殊方法,也可以重写特殊方法
#创建一个类
class Person():
def run(self):
print('人在跑')
def sleep(self):
print('人在睡觉')
#创建一个特殊方法,并设置属性
def __init__(self,name):
#封装
self._name = name
@property #装饰器getter方法(查看name属性值)
def name(self):
return self._name
@name.setter #装饰器setter方法(修改name属性值)
def name(self,name):
self._name = name
class teacher(Person):
def run(self):
print('老师在跑')
def sleep(self):
print('老师在睡觉')
p1 = teacher('大师')
p1.name = '程序员'
print(p1.name)
运行结果:
程序员
super() 可以获得当前类的父类
# 创建一个类
class Person():
def __init__(self, name):
self._name = name
def speak(self):
print('%s在跑' % self._name)
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
# 创建第二个类
class students(Person):
def __init__(self, name, age):
self._name = name
self._age = age
# super()这个方法就是在创建类时,类的父类是谁,就调用谁
super().__init__(name) # 让子类students调用父类Person的方法
def speak_age(self):
print('我的年龄是%s' % self._age)
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
a = students('Python程序员',18)
a.speak()
a.speak_age()
print(a.name)
print(a.age)
运行结果:
Python程序员在跑
我的年龄是18
Python程序员
18
总结:
super()的好处:super()方法的漂亮之处在于,你不需要定义子类的构造器时,明确的指定子类的基类并显式的调用,即不明确的提供父类。这样做的好处就是,如果你改变了继承的父类,你只需要改继承的父类,而不需要在大量代码中去寻找那个要修改的基类,另一方面,代码的可移植性和重用性也更高
多重继承
语法用法:类名.__bases__
__bases__用来获取当前定义的类的父类
在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
class A():
pass
class B(A):
pass
class C(B,A): #注意:继承可以单继承,也可以多继承
pass
print(C.__bases__)
运行结果:
(<class '__main__.B'>, <class '__main__.A'>)
在开发过程中没有特殊情况,尽量避免使用多重继承,因为多重继承会我们的代码的过于复杂,如果多个父类中有同名的方法,则会在第一个父类中寻找,如果有则调用,没有则去第二个父类中寻找,以此类推.(当父类中有同名的方法时,则前面的父类会覆盖后面的父类方法)
class A(object):
def speak(self):
print('我是A方法')
class B(object):
def speak1(self):
print('我是B方法')
class C(B,A): #先去类中定义的第一个父类中寻找,如果有,则使用。如果没有,则去第二个父类中寻找,以此类推
pass
c = C()
c.speak()
运行结果:
我是A方法
多态
多态是面向对象的三大特征之一
一个对象可以以不同的形态去呈现
class A():
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class B():
def __len__(self):
return 10
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
a =A('光头强')
b =B('大耳朵图图')
def speak(obj):
print('你好我是%s'%obj.name)
def speak1(obj):
#做类型检查
#违反了多态的函数只适用于一种类型的对象,无法处理其他类型的对象,这样会导致函数的实用性很差
#通用性比较差,但他的好处就是不容易出错
if isinstance(a,A):
print('经过检查%s是A的属性'%obj.name)
# speak1(a)
# speak(a)
# print(len(b))
属性和方法
类属性
类属性,直接在类中定义的属性就是类属性
类属性可以通过类本身或类实例访问
类属性只能通过类修修改,无法通过实例对象来修改
class math():
count = 0 # 定义一个类属性,类属性只能通过类修改,无法通过实例对象修改
a = math() # 创建一个实例对象
print(a.count) # 通过实例来读取
print(math.count) # 通过类属性来读取
math.count = 20 # 当通过类属性来修改类值之后,实例对象的值也会跟着改变
# print(a.count) #(当通过实例对象来修改属性的时候,修改的是属性值,并不是类的属性值,类属性值不会受到影响)
print(a.count)
print(math.count)
运行结果:
0
0
20
20
什么是实例方法?
实例对象就是实例方法在类中直接定义的
在类中定义的,以self为参数的方法都是实例方法
实例方法在调用时,Python会将调用的对象作为self传入
当通过类调用时,不会自己传入self
实例属性
实例属性通过实例对象添加的属性叫做实例属性
实例属性只能通过实例对象来访问和修改,对象无法访问和修改
class Person():
# 这个特殊方法也是实例方法,因为他只能通过实例对象来访问
def __init__(self,name):
self._name = name
def speak(self): # 在类中以self为参数的都是实例方法
print('%s正在讲话'%self._name)
a = Person('Python程序员')
a.speak()
Person.speak(a) #通过类调用时,不会自动传入self
运行结果:
Python程序员正在讲话
Python程序员正在讲话
类方法
通过@classmethod来修饰的方法是类方法.(注意:类方法可以操控类的属性)
类方法的第一个参数是cls,会自己传递,cls就是当前类的类对象.类方法和实例方法的区别,实例方法第一个参数是self,而类方法第一个传递的是cls.
类方法也可以通过实例方法来调用
class Person():
count = 10
# 这个特殊方法也是实例方法,因为他只能通过实例对象来访问
def __init__(self,name):
self._name = name
def speak(self): # 在类中以self为参数的都是实例方法
print('%s正在讲话'%self._name)
@classmethod #类方法
def text(cls): #类方法默认传递cls
print('我是Person当中的类方法')
print(cls.count)
a = Person('Python程序员')
Person.text() #类方法通过类来调用则不需要传递参数
a.text() #类方法也可以通过实例对象来调用
#总结:类方法和实例方法一个本质上的区别就是:类方法第一个默认传参是cla,而实例方法是self
运行结果:
我是Person当中的类方法
10
我是Person当中的类方法
10
静态方法
在类中内部使用@staticmethod来修饰的方法属于静态方法,静态方法不需要指定的任何默认的参数,静态方法可以通过类和实例去调用
(静态方法的好处是:可以通过类去调用该方法,让编译器不能直接调用,相当于是保存到类中的一个函数)
class Person():
count = 10
# 这个特殊方法也是实例方法,因为他只能通过实例对象来访问
def __init__(self,name):
self._name = name
def speak(self): # 在类中以self为参数的都是实例方法
print('%s正在讲话'%self._name)
@classmethod #类方法
def text(cls): #类方法默认传递cls
print('我是Person当中的类方法')
print(cls.count)
#静态方法
@staticmethod
def text2(): #静态方法里面不需要传递任何参数,静态方法可以通过类和实例去调用
print('这个是Person当中的类方法')
a = Person('Python程序员')
# Person.text() #类方法通过类来调用则不需要传递参数
# a.text() #类方法也可以通过实例对象来调用
# #总结:类方法和实例方法一个本质上的区别就是:类方法第一个默认传参是cla,而实例方法是self
Person.text2()
a.text2()
运行结果:
这个是Person当中的类方法
这个是Person当中的类方法