Python与C++、Java等众多语言一样,被视为一种面向对象的语言。
如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。
一、类定义
一个简单的类定义如下:
class Person: def set_name(self, name): self.name = name def get_name(self): return self.name def greet(self): print("Hello, world! I'm {}".format(self.name))
这里Person是类的名称。 Class语句创建独立的命名空间。
>>> p = Person() >>> p.set_name('Mike') >>> p.greet() <__main__.Person object at 0x100614e10>
<class '__main__.Person'>
Hello, world! I'm Mike
每个与类相关联的方法都会自动传递出参数self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
实际上,可以随便给这个参数命名,但鉴于它总是指向对象本身,因此习惯上将其命名为self。
self会自动传递,因此我们不需要传递它。
二、构造函数
类有一个名为 __init__() 的特殊方法称为构造函数,该方法在类实例化时会自动调用。
__init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:
class Person: def __init__(self, name): self.name = name print('__init__') print(self.name)
实例化Person以及输出的结果示例为:
>>> p = Person('John') __init__ John
以self为前缀的变量可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。
self.name = name获取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。
三、属性
1、给属性指定默认值
类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。
class Person: def __init__(self, name, age): self.name = name self.age = 8
2、修改属性的值
可以通过实例或者类方法对属性进行修改。
class Person: def __init__(self, name): self.name = name self.age = 8 print('name:', self.name) def set_name(self, name): self.name = name print('name:', self.name) p = Person('Mike') p.name = 'Jack' print('name:', p.name) p.set_name('Rose')
输出结果为:
name: Mike
name: Jack
name: Rose
四、继承
一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。
子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
1、子类的构造函数__init__()
在子类的构造函数里,必须调用父类的构造函数,这样才能正确的初始化对象。
class Car: """汽车""" def __init__(self, make, model, year): self.make = make self.model = model self.year = year def get_descriptive_name(self): long_name = str(self.year) + ' ' + self.make + ' ' + self.model return long_name.title() class ElectricCar(Car): """电动汽车的独特之处""" def __init__(self, make, model, year): """初始化父类的属性""" super().__init__(make, model, year)
2、子类的属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
class ElectricCar(Car): """电动汽车""" def __init__(self, make, model, year): """ 电动汽车的独特之处 初始化父类的属性,再初始化电动汽车特有的属性 """ super().__init__(make, model, year) self.battery_size = 70 def describe_battery(self): print("This car has a " + str(self.battery_size) + "-kWh battery") my_tesla = ElectricCar('tesla', 'model s', 2019) print(my_tesla.get_descriptive_name()) my_tesla.describe_battery()
输出结果为:
2019 Tesla Model S
This car has a 70-kWh battery
3、重写(覆盖)父类的方法
如果子类定义的方法与父类方法同名,则调用子类实例的时候Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
假设Car类有一个名叫fill_gas_tank()的方法,它对全电动汽车来说毫无意义,因此我们可以重写它。
class ElectricCar(Car): --snip-- def fill_gas_tank(self): """电动汽车没有油箱""" print("This car doesn't need a gas tank!")
现在如果我们对电动汽车调用fill_gas_tank(),Python将忽略Car类中的方法fill_gas_tank()。
五、静态方法和类方法
1、静态方法
静态方法的装饰器为staticmethod。
静态方法的定义中没有参数self,可直接通过类来调用,表示该方法与具体实例无关。
class MyClass: @staticmethod def smeth(): print("This is a static method")
可像下面这样直接使用:
>>> MyClass.smeth() This is a static method
2、类方法
类方法的装饰器为classmethod。
类方法的定义中包含类似于self的参数,通常被命名为cls。类方法也可以通过类直接调用,参数cls将自动关联到类。
class MyClass: @classmethod def cmeth(cls): print("This is a class method of", cls)
可像下面这样直接使用:
>>> MyClass.cmeth() This is a class method of <class '__main__.MyClass'>
六、抽象基类
抽象基类是不能(至少是不应该)实例化的类,其职责是定义子类应实现的一组抽象方法。
Python通过引入模块abc提供了官方解决方案,这个模块为抽象基类提供了支持。
下面是一个简单的示例:
from abc import ABC, abstractmethod class Talker(ABC): @abstractmethod def talk(self): pass
抽象类不能实例化,并且没有实现抽象方法的子类也不能实例化:
class Knigger(Talker): pass
>>> Talker() Talker() TypeError: Can't instantiate abstract class Talker with abstract methods talk >>> Knigger() Knigger() TypeError: Can't instantiate abstract class Knigger with abstract methods talk
我们可重新编写子类,实现要求的方法:
class Knigger(Talker): def talk(self): print("Hi!")
>>> k = Knigger() >>> k.talk() Hi!