面向对象
继承
继承让类与类之间产生了关系,有了这层关系,才有我们后续要说的多态。
继承的引入
我们先来定义一个动物类:
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
a=Animal()
a.sleep()
那如果现在我又想定义一个狗类呢?
我有三种思路:
1.直接在动物类上修改,可以添加上一些狗的独有功能。
但这样做的话修改起来会比较麻烦,而且还违反了ocp原则。
2.创建一个新的类(狗类)
这样子的话同样比较麻烦,我们需要大量的复制粘贴
3.直接从Animal类中继承他的属性和方法
在定义类的时候可以在类名后的括号中指定当前类的父类(超类,基类)
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
class Dog(Animal):
pass
d=Dog()
d.run()
我们来看输出结果:
我们并没有在Dog类中定义run()方法,但是最后能够输出结果,说明了这个Dog类继承了Animal类,在Animal类中有run方法。
同样我们能在这个基础上定义狗所独有的功能,我们可以再定义一个方法:
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
class Dog(Animal):
def speak(self):
print('汪汪汪')
d=Dog()
d.run()
d.speak()
输出结果:
在创建类的时候,如果省略了父类,则默认父类为object。如class Animal(object):
issubclass(): 检查一个类是不是另外一个类的子类。
如我们在上面代码在加上一行
print(issubclass(Dog,Animal))
它的返回结果为True,Dog确实为Animal的子类。
我们来试试加上这几行代码:
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
class Dog(Animal):
def speak(self):
print('汪汪汪')
d=Dog()
d.run()
d.speak()
print(issubclass(Dog,Animal))
print(issubclass(Dog,object))
print(issubclass(Animal,object))
print(issubclass(int,object))
print(issubclass(Dog,int))
通过这可以看到object是所有类的父类。
方法的重写
如果在子类中有和父类重名的方法,则通过子类实例去调用该方法时会调用子类的方法,而不是父类中的方法。这个特点我们称之为方法的重写(覆盖)
class A(object):
def test(self):
print('A...')
class B(A):
def test(self):
print('B...')
class C(B):
pass
c=C()
c.test()
如果A,B类中都没有test()方法,该程序就会报错。
如果B类中没有test()方法,则会输出A…
当我们调用一个对象的方法时
会优先去当前对象中寻找是否具有该方法,如果有则直接调用。
如果没有则去当前对象的父类中寻找,如果父类中有,则直接调用父类中的方法。
如果还没有,则去父类中的父类寻找,以此类推,直到找到object,如果依然没找到就报错。
super()
class Animal(object):
def __init__(self,name,age,height):
self._name=name
self._age=age
self._height=height
@property
def name(self):
return self._name
def age(self):
return self._age
@name.setter
def name(self,name):
self._name=name
def age(self,age):
self._age=age
class Dog(Animal):
def __init__(self,name,age,height,weight):
super().__init__(name,age,height)
self._kanjia=weight
@property
def weight(self):
return self._kanjia
print('狗会看家')
@weight.setter
def kanjia(self,kanjia):
self._kanjia=kanjia
d=Dog('小黄','3','3','3')
d.name='小奶狗'
print(d.name)
看上面这个例子,我们用了super()
在这个例子里我们定义了,name,age,height,weight这几个属性,使用super()这个方法,我们就直接在他后面加上父类有的属性,然后单独写子类独有的属性。假如我们不用super()方法,我们就得写上:
self._name=name
self._age=age
self._height=height
这样写就比较复杂了,要是有很多属性,我们还得写很多这样的代码。所以使用super()方法就方便多了。
多重继承
在python中是支持多继承的,也就是我们可以为一个类指定多个父类,如果多个父类中出现同名的方法,则会先在第一个父类中寻找,然后是第二个…以此类推。
class A(object):
def test1(self):
print('A...')
class B(object):
def test1(self):
print('B中test1的方法')
def test2(self):
print('B...')
class C(A,B):
pass
c=C()
c.test1()
就像这样现在第一个父类中寻找,第一个父类中有所以输出A…
多态的简介
多态是面向对象的三大特征之一
class A(object):
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(object):
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)
speak(a)
speak(b)
现在我来把代码改成这样:
class A(object):
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(object):
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):
if isinstance(obj,A):
print('好好复习%s'%obj.name)
speak(b)
没有输出结果,这就违反了多态。
我们常见的一个==len()==函数体现的就是一种多态
lst=[1,2,3,4,5,6,7,8]
str='python'
print (len(lst))
print (len(str))
不管是什么类型,len()函数都能输出他们的长度。
面向对象的三大特性
- 封装 :确保对象中的数据安全
- 继承:保证了对象的可拓展性
- 多态:保证了对象的灵活性**
属性和方法
类属性:直接在类中定义的属性
类属性可以通过类和该类的实例来访问
class A(object):
count=0
a=A()
print(a.count)
print(A.count)
实例属性:通过实例来添加的属性就是实例属性
类中的属性只能通过类对象来修改,无法通过实例对象来修改
我们来看下面这两串代码
class A(object):
count=0
a=A()
a.count=10
print(a.count)
print(A.count)
我们可以看到修改了实例属性为10,类属性还是0没有改变
class A(object):
count=0
a=A()
a.count=10
A.count=20
print(a.count)
print(A.count)
我们可以看到只有通过修改类对象来修改类属性。
实例属性只能通过实例对象来访问,类对象无法访问和修改
class A(object):
count=0
def __init__(self):
self.name='葫芦娃'
a=A()
print(a.name)
class A(object):
count=0
def __init__(self):
self.name='葫芦娃'
a=A()
print(A.name)
报错了,类对象不能访问
当通过实例对象调用时,会自动传递当前对象作为self传入
当通过类去调用时,不会自动传递self
class A(object):
count=0
def __init__(self):
self.name='葫芦娃'
def test(self):
print('这是一个test方法')
a=A()
a.test()
如果通过类调用呢?
class A(object):
count=0
def __init__(self):
self.name='葫芦娃'
def test(self):
print('这是一个test方法')
a=A()
A.test()
报错
没有self这个参数,所以我们要怎么做呢
class A(object):
count=0
def __init__(self):
self.name='葫芦娃'
def test(self):
print('这是一个test方法')
a=A()
A.test(a)
成功执行了。
实例方法可以通过类对象调用,也可以通过实例对象去调用。
a.test()等价于A.test(a)
**类方法:**在类的内部使用@classmethod来修饰的方法属于类方法,类方法的第一个参数我们习惯写成cls,cls就相当于当前的类对象
class A(object):
count=0
@classmethod
def test(cls):
print('这是一个test方法')
print(cls.count)
a=A()
A.test()
class A(object):
count=0
@classmethod
def test(cls):
print('这是一个test方法')
print(cls.count)
a=A()
a.test()
从上面可以看出类方法可以通过类对象调用,也可以通过实例对象来调用。
A.test()等价于a.test()
静态方法
在类中用@staticmethod来修饰的方法我们称之为静态方法。
不需要制定任何的默认参数,静态方法可以被类对象和实例对象来调用:
class A(object):
count=0
@staticmethod
def test():
print('这是一个test方法')
a=A()
A.test()
a.test()