python08-面向对象编程基础

时间:2022-12-20 13:58:18

面向对象编程(Object Oriented Programming, OOP),对象中包含了数据与对数据进行操作的方法。python中自定义的对象即是类(class),类定义的一个个实体叫做实例(instance)。

1 类与实例

>>> class lover(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def print_lover(self):
print('%s %s'%(self.__name,self.__age))
>>> lover1 = lover('sui',20)

1.1 类的定义形式为

class+类名+()

()中的内容是该类需要继承的类,如果没有的话就写object,因为所有类都要继承这个类。

1.2 显而易见,在类中定义的函数的第一个参数一定是self,但是在调用函数的不用传该参数,因为python会自动把当前实例传进去。

1.3 第一个函数__init__是类的初始化,定义了类的属性(property),在创建实例的时候必须传进与__init__函数相对用的参数,否则将报错。

1.4 在Python中,实例的变量名如果以__(双下划线)开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。比如在上边定义的name属性和age属性都使用了双下划线开头,这时候再在外部使用 lover1.__name就会报错。需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。(廖雪峰)

1.5 实例的定义方法非常简单, 实例名=类名+(属性值)

1.6 还有一点就是,对于python这种动态语言来说,不同的实例可以绑定不同的属性或方法,比如我定义了两个实例:

lover1 = lover(‘sui’,20)
lover2 = lover(‘sun’,18)

我可以给lover1多绑定一个gender属性,而lover2则没有该属性。

>>>lover1.gender = ‘male’
>>> lover1.gender
'male'
>>> lover2.gender
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
lover2.gender
AttributeError: 'lover' object has no attribute 'gender'

2 继承

继承呢,简单说就是:你爸的东西是你的,但是你的不一定是你爸的。
继承的类叫做子类(subclass),被继承的类叫做父类或是基类(base class)。子类将拥有父类的所有属性和方法。但是如果子类中定义了与父类相同的方法,那么有效的是子类的,也就是说完成了覆盖。
举例如下:

>>> class Animal(object):
def print_run(self):
print('Animal is running.')
>>> class Dog(Animal):
pass
>>> class Cat(Animal):
pass

Dog和Cat都是Animal的子类,尽管他们的定义中什么都没有,但是将会继承父类Animal的print_run函数。

>>> cat = Cat()
>>> dog = Dog()
>>> dog.print_run()
Animal is running.
>>> cat.print_run()
Animal is running.

如果改写一下Dog类的内容,给他也定义一个print_run方法,则:

>>> class Dog(Animal):
def print_run(self):
print('Dog is runnning')
>>> dog = Dog()
>>> dog.print_run()
Dog is runnning

可见,现在变成Dog is running了,子类的方法覆盖了父类。

3 多态

经过前面的继承以后,有一个小问题,实例dog的数据类型是Dog

>>> isinstance(dog,Dog)
True

那么isinstance(dog,Animal)的结果是什么呢?结果是 True
所以说子类的实例的数据类型不仅可以是本身,也可以是父类。

这样就产生了多态的这个概念:同一个实现接口,使用不同的实例而执行不同的操作。

多态的实现步骤一般是:

  1. 写一个方法,它只接收父类作为参数,编写的代码只与父类打交道。
  2. 子类重写父类的方法。使子类具有不同的方法实现。
  3. 运行时,根据实际创建的对象类型动态决定使用那个方法。

下面进行举例:
首先写一个函数,他的参数是一个父类:

>>> def something_run(Animal):
Animal.print_run()

由于在前面已经为Dog和Cat都重写了print_run方法,所以直接实验。

>>> ani = Animal()
>>> something_run(ani)
Animal is running.
>>> something_run(dog)
Dog is running

所以可见多态的好处就是,函数是不用做修改的,只需要重写每个子类的方法就好了。使代码简洁易修改。
其实,对于python来说,传入的参数甚至不用是Animal或是Animal的子类都可以,只要你这个类中有print_run这个方法就可以了。这被称为“鸭子类型”,这是动态语言的特点!