1. 继承简介
- 继承是面向对象的三大特性之一
- 在定义类 时 我们可以在类的 括号里面指定 当前的父类
- 继承的特性:
- 继承提高了代码的复用性
- 继承使类与类之间产生了关系。 有了关系,才有了多态的特性
2. 方法重写
- 如果子类和父类有同名的方法。则通过子类实例去调用方法时,会调用子类的方法,而不是父类的方法,此过程我们称之为方法的重写(覆盖)
- 当我们调用一个对象时:
- 会优先去当前对象的父类中寻找,如果有,则调用。
- 如果没有,则会去父类的父类中寻找,如果有,则调用
- 如果没有,以此类推,直到找到 object 如果依然没有找到就会直接报错
class A():
def test(self):
print('A......')
class B(A):
def test(self):
print('B......')
class C(B):
def test(self):
print('C......')
def text(self):
print('text....')
a = C()
a.test()
a.text()
b = B()
b.test()
3. super()
- super()可以直接获取当前类的父类
- 并且通过super()返回对象调用父类方法时,不需要传递self
父类中的所有方法都会被子类继承,包括特殊方法,否则就会报错
class Animal():
def __init__(self, name):
self._name = name
def run(self):
print('动物跑....')
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
def sleep(self):
print('动物睡觉....')
class Dog(Animal):
def speak(self):
print('汪汪....')
d = Dog() # TypeError: __init__() missing 1 required positional argument: 'name'
所以我们将父类的特殊方法传进来,但是子类的特殊方法会将父类的特殊方法给覆盖掉
class Animal():
def __init__(self, name):
self._name = name
def run(self):
print('动物跑....')
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
def sleep(self):
print('动物睡觉....')
class Dog(Animal):
def __init__(self, name, age):
self._name = name
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def speak(self):
print('汪汪....')
d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name)
print(d.age)
如果,父类的_init_()方法中有很多的参数,如果如传递的话,会被覆盖掉,而传递过来的话,会增大代码量,有什么方法可以解决吗?
class Animal():
def __init__(self, name):
self._name = name
def run(self):
print('动物跑....')
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
def sleep(self):
print('动物睡觉....')
class Dog(Animal):
def __init__(self, name, age):
# 直接调用父类_init_方法,而且还省略了self._name = name步骤,如果参数很多,可以减少代码量
Animal.__init__(self, name)
# self._name = name
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def speak(self):
print('汪汪....')
d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name) # 萨摩耶
print(d.age) # 8
这样做的话,还有一个问题,这样的调用方法把父类给写死了,如果更换了父类,我们还得更换父类的_init_方法。所以,super() 可以彻底解决这个问题
class Animal():
def __init__(self, name):
self._name = name
def run(self):
print('动物跑....')
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
def sleep(self):
print('动物睡觉....')
class Dog(Animal):
def __init__(self, name, age):
# 直接调用父类_init_方法,而且还省略了self._name = name步骤,如果参数很多,可以减少代码量
# Animal.__init__(self, name)
# 只需要选择传入的参数即可,不会考虑父类是否更换
super().__init__(name)
# self._name = name
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def speak(self):
print('汪汪....')
d = Dog('二哈', 8) # TypeError: __init__() missing 1 required positional argument: 'name'
d.name = '萨摩耶'
print(d.name) # 萨摩耶
print(d.age) # 8
4. 多重继承
- 在Python中是支持多重继承的,也就是一个类可以同时拥有多个父类
- 可以在类名()里面添加多个类,来实现多重继承
- 多重继承可以使子类同时用有多个父类,并且会获取到所有父类中的方法
- 在开发中没有特殊情况应该避免使用多重继承。因为多重继承会使代码更加复杂
- 如果多个父类中有同名的方法,则会在第一个父类中寻找,然后是第二个、第三个,前面的回覆盖后面的
class A():
def test(self):
print('A中的test....')
class B(object):
def testB(self):
print('B中的test....')
def test(self):
print('B....')
class C(A,B):
pass
# def testC(self):
# print('C中的test....')
c = C()
c.test() # A中的test....
class A():
def test(self):
print('A中的test....')
class B(object):
def testB(self):
print('B中的test....')
def test(self):
print('B....')
class C(B, A):
pass
# def testC(self):
# print('C中的test....')
c = C()
c.test() # B....
如果第一个类中没有该方法怎么办
class A(object):
pass
class B(object):
def testB(self):
print('B中的test....')
def test(self):
print('B....')
class D(object):
def test(self):
print('D.....')
class C(A, B, D):
pass
# def testC(self):
# print('C中的test....')
c = C()
c.test() # B....
5. 多态
- 多态是面向对象的三大特性之一, 多态保证程序的灵活性
- 一个对象可以以不同的形式去出现
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 __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
class C:
pass
a = A('葫芦娃')
b = B('钢铁侠')
c = C()
def speak(obj):
# 对于该函数来说只要对象中有name属性 就可以使用,它就可以作为参数传递
# 不考虑对象的类型。只要有name属性就可以
print('Hello %s' % obj.name)
speak(a)
def speak2(obj):
# 该函数只允许A类的实例进行输出,而其他类型的对象无法使用该函数,这样的话就违反了多态
if isinstance(obj, A):
print('Hello %s' % obj.name)
# print('Hello {}'.format(obj))
speak2(a)
举例:len()函数就是一个典型的多态函数
lst = [1, 2, 3, 4]
s = 'python'
print(len(lst)) # 4
print(len(s)) # 6
class B:
def __init__(self, name
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
print(len(b)) # TypeError: object of type 'B' has no len()
# 只要对象中有__len__特殊方法,就可以通过len()函数获取到长度的结果
class B:
def __len__(self):
return 100
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
print(len(B)) # 100
6. 属性和方法
- 类属性
- 类属性直接在类中定义的属性
- 类属性只能通过类和类的实例才能访问的到,但是类属性只能通过类对象来修改,实例对象无法修改
class A:
count = 0
a = A()
print(A.count) # 0
print(a.count) # 0
# 类属性只能通过类对象来修改,实例对象无法修改——> 类对象和实例对象的值都为100
class A:
count = 0
a = A()
A.count = 100
print(A.count) # 100
print(a.count) # 100
# 我们试着用实例对象去修改会有什么效果——> 类对象的属性值仍然为0,但是实例属性的值为1
class A:
count = 0
a = A()
a.count = 1
print(A.count) # 0
print(a.count) # 1
- 实例属性
- 实例属性是通过实例对象添加的属性
- 实例属性只能通过实例对象才能访问和修改,类对象无法访问和修改
class A(object):
count = 0
def __init__(self):
# 实例属性 通过实例对象添加的属性
self.name = '钢铁侠'
# 实例属性只有实例对象才能访问和修改,类对象无法访问和修改
a = A()
print(a.name) # 钢铁侠
# 如果类对象进行访问和修改的话,会报一个属性错误
print(A.name) # AttributeError: type object 'A' has no attribute 'name'
- 方法
- 类方法
- 类方法的格式:@classmethod
- 类方法传递的第一个参数是 cls 。 cls 是当前类的参数
- 类方法可以通过实例对象和类对象去调用,而且实例对象调用类方法的时候不需要传入 cls 参数
- 实例方法
- 在类定义中,以self为第一个参数的方法皆为实例方法
- 实例方法在调用的时候,Python会将当前的调用对象以 self 传入, self = 调用对象
- 实例方法可以通过实例和类去调用
- 通过类去调用实例方法时,需要手动传入 self 参数
- 即 实例对象.实例方法() = 类对象.实例方法(实例对象)
class A(object):
count = 0
def __init__(self):
# 实例属性 通过实例对象添加的属性
self.name = '钢铁侠'
# 实例方法
# 在类定义中以第一个self参数传入的的都是实例方法
# 实例方法在调用的时候,Python会自动将调用对象以self参数传入
# 类方法调用的时候需要手动传入self参数
def test(self):
print('Hello test....')
# 类方法
# 类方法需要传入cls参数
@classmethod
def speak(cls):
print('Hello speak....')
print(cls.count)
a = A()
a.test() # Hello test....
# 当类方法去调用的时候,不会自动传入self,需要手动去传入一个self参数,否则会报属性错误
# A.test() # TypeError: test() missing 1 required positional argument: 'self'
A.test(a) # Hello test....
# a.test() = A.test(a)
A.speak() # Hello speak.... 0
a.speak() # Hello speak.... 0
# 即A.speak() = a.speak()
- 类方法和实例方法的区别:
- 实例方法传入的第一参数是self,而类方法传入的第一个参数是cls
- 类方法需要@classmethod 作为装饰器
- 静态方法
- 语法:@staticmethod
- 静态方法不需要指定任何默认参数
- 静态方法可以通过类和实例调用
- 静态方法基本上是一个和当前类无关的方法。它只是一个保存到当前类的函数
- 静态方法一般是工具方法,与当前类无关
class A(object):
@staticmethod
def text():
print('Hello text....')
a = A()
a.text() # Hello text....
A.text() # Hello text....