此系列文章的创作初衷是作为读书过程中的笔记,而非教程类文章。
第9章 类
9.1 创建和使用类
- 下面是创建一个类的样例代码:
class Dog():
""" 一次模拟小狗的简单尝试 """
def __init__(self, name):
self.name = name
def sit(self):
print(self.name.title() + "is now sitting.")
可以发现以下特点:
- 可以在创建类时向类名传入参数。这里没有传入任何参数,表示从空白创建类(没有父类)。
- __init__是python中的构造方法,每创建一个实例时,python都将调用此构造方法。
- python中无需单独定义属性(在Java中称为数据域或成员变量),属性在构造函数中定义。类的任何方法以及任何实例都可以访问某一实例的属性。
- 类中方法的第一个参数必须为self,这是一个指向对象自身的指针,类似于Java中的this。在调用方法时,self自动传入。
- 推荐用添加函数注释的方法,为类也添加注释。
注:Python对成员(变量/方法)没有严格的访问权限控制,所有成员对外部都是可访问的(类似Java public)。可以通过将成员命名为以双下划线开头,这样成员将不可由外部直接访问(类似Java private),但仍可以用 _类名__成员名 的方法访问(对子类不适用:只能用父类提供的公有方法访问),本质上是一种障眼法。
- 实例化一个对象的样例代码:
dog = Dog("Willie")
通过类名调用构造函数实例化一个对象,并将对象关联到一个变量,即可实现对象的实例化。
- 可以通过句点访问实例的属性和方法
print(dog.name)
dog.sit()
9.3 继承
- 一段用于展示继承的样例代码:
class Car():
def __init__(self, model, maker, year):
self.model = model
self.maker = maker
self.year = year
self.__hidden = 0
def describe(self):
caption = str(self.year) + " " + self.maker.title() + " " + self.model.title()
print("This is a " + caption + ".")
class Battery():
def __init__(self, capacity):
self.capacity = capacity
def reportRange(self):
print("This battery can sustain approximately " + str(4 * self.capacity) + " miles on a full charge.")
# ElectricCar继承Car类
class ElectricCar(Car):
def __init__(self, model, maker, year, batteryCapacity=60):
super().__init__(model, maker, year) # 调用父类构造函数
self.battery = Battery(batteryCapacity) # 以一个Battery对象作为子类的新属性
# 新方法
def batteryReport(self):
self.battery.reportRange()
# Override, 不推荐的做法
def describe(self, arg):
super().describe() # 可以在重写方法中调用被重写的方法
self.batteryReport()
tesla = ElectricCar("Model S", "Tesla", 2018)
tesla.describe(0)
- 创建子类时,父类的代码必须位于同一文件内(或使用import导入),且位于子类的定义之前。定义子类时,在括号内指定父类的名称。
- 子类将自动拥有父类的所有方法和属性,并可通过super()来调用父类的构造函数对继承自父类的属性进行初始化。
- 当父类定义的方法不适用于子类模拟的实体时,可以对方法进行重写,做法是定义一个名称相同的方法。名称相同,但形参表不同的方法也作为重写方法处理(Python中没有方法重载),但不推荐这样做,PyCharm将给出一个warning。
9.4 导入类
- 可以将类封装于.py文件中作为模块。在其他文件中可以导入此模块并使用模块中的类,就像导入函数模块一样。
- 推荐在模块的开头用文档字符串简要描述整个模块。
- 类似于函数模块,可以用以下方法导入模块中的类:
- import module: 使用module.class的方式访问模块中的类。
- from module import class1, class2, …: 可以直接使用模块中的类,在存在同名类的情况下,模块中的类将被本文件中的类覆盖。
- from module import *: 不推荐。相比import module方法,容易造成命名冲突问题;相比from module import方法,不能清晰地获悉使用了哪些类。
- 可以在一个模块中导入另一个模块,导入方式与在普通文件中导入时完全相同。当存在文档字符串时,推荐将文档字符串置于导入语句之前。