面向对象(Object Oriented)是一种设计思想,面向对象编程OOP(Object Oriented Programming)就是用面向对象的思想去编程。这里的对象通常就是我们用程序抽象化出来的,用于模拟客观存在的事物,比如汽车,飞机等。当然对象也不限于具体的事物,也可以是抽象的,比如四边形,三角形圆。

对象本身就是一个抽象的概念,通常包含静态的'属性',比如汽车的颜色,座位数,制造商;包含动态的'方法',比如汽车可以行驶,鸣笛,加速。在程序世界,用类来抽象某一事物,并且封装对象的基本属性和方法,并且通过类来创建该类的实例对象。下面我们看一下类的定义及对象声明。

class Person:
  name = ''
  age = 0
  def __init__(self,name,age):
    self.name = name
    self.age = age
  def say(self):
    print('我是%s 年龄%d'%(self.name,self.age))
p = Person('小麦',25)
p.say()
#结果:我是小麦 年龄25

如上,通过class关键字来定义一个类,后面紧跟类的名称,一般使用驼峰命名方式,name和age是Person类的属性,say是Person类的方法,声明对象实例时,直接使用类名加'()'即可。

类的方法和函数本质上没有什么区别,但是类的成员方法第一个参数被冠以self,表示当前的实例对象,我们可以通过对象内存地址验证下。

class Car:
  def __init__(self):
    print(self)
car = Car()
print('car:',car)
#结果:
<__main__.Car object at 0x0000029045AA74C0>
car: <__main__.Car object at 0x0000029045AA74C0>
 可以看到self就是当前声明的类实例对象。下面我们对比看下类属性和实例属性。定义在类级别的属性称之为类属性,这是所有实例化对象共用的,定义在方法中的属性,属于实例属性,作用域限定在当前实例。
class Car:
  color = 'black'
  def __init__(self,color):
    self.color = color
    self.seats = 5
  def say(self):
    print(Car.color,self.color,self.seats)
car = Car('white')
car.say()
#结果:black white 5

我们可以使用类名.类属性访问类的属性,也可以使用实例名.类属性访问,但是使用类名访问实例属性会抛出异常。

下面我们看一下属性和方法的访问限制,大家注意到了上面的init方法名称使用双下划线开头并以双下划线结尾,这一般都是系统定义的名字,init是类的初始化构造方法,我们只是重新定义了一个构造方法。

通常以单下划线'_'开头,表示受保护(protected)的类成员,只允许类本身和子类访问,不允许from module import * 语句导入;双下划线'__',表示私有(private)成员,只允许类本身进行访问,类实例也不能直接访问。

class Animal:
  """动物类"""
  _name = '小麦'
  __nick_name = '小麦菜'
  def __init__(self):
    print('Animal __init__:',Animal.__nick_name)
animal = Animal()
try :
  print('直接访问私有变量:',animal.__nick_name)
except AttributeError:
  print('类实例不能直接访问私有变量',animal._Animal__nick_name)
#结果:
Animal __init__: 小麦菜
类实例不能直接访问私有变量 小麦菜

 私有成员变量可以使用实例名._类名__私有变量来访问,通常我们应该尽量少暴露类的关键属性,而是通过通过暴露方法,以提供只读访问。下面我们通过@property装饰器作用在方法上,用来对外提供访问。

class Circle:
  def __init__(self,radius):
    self.__PI = 3.14
    self.__radius = radius
  @property
  def area(self):
    return 3.14 * self.__radius ** 2
circle = Circle(5)
print(circle.area)

如上,使用@property装饰器后,我们可以直接使用area属性获取面积计算结果。最后我们看一下类的继承,类的定义就是为了抽象,那么类的公共属性当然也要抽象出去,被继承的类称之为超类,继承的类称之为子类。

class Student(Person):
  grade = ''
  def __init__(self,name,age,grade):
    Person.__init__(self,name,age)
    self.grade = grade
  def say(self):
    print('我是:%s 年龄:%d 年级:%s' % (self.name, self.age,self.grade))
s = Student('小麦',25,'1')
s.say()

 类的继承很简单,在类后面的括号里写上要继承的类即可,多个类用逗号分隔,如上我们声明一个Student类继承自Person类,并为子类添加grade属性,我们重写一下超类的say方法,我们在init方法中首先调用了超类的init方法。

面向对象就是把事物封装归类,并抽象出重复的特征,子类可以继承超类的共性,同时子类可以有自己的个性。这就是面向对象基本的特点,封装、继承、多态。今天我们就分享到这里,下一节我们讲python3以强大模块著称的模块,是比函数模块更大的概念。