Python Class
简介¶
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。
面向对象技术简介¶
-
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
-
实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
何时使用类¶
- 数据与操作紧密相关
- 对象有许多状态需要维护,可以使用类中的属性来保存状态。
- 需要生成多个仅在部分属性不同的实例,可以使用类作为模板。
- 不同对象存在公共parent-child的层次关系,可以使用继承来复用代码。
- 隐藏对象的实现细节,只对外公开接口。
类变量 与 实例变量¶
在Python中,类变量和实例变量是两个不同的概念:
-
类变量(Class Variable)
-
定义在类内部,但不在任何方法之内
- 被该类的所有实例对象所共享
- 可以通过类名或实例对象访问
-
用于定义与这个类相关的特征或属性
-
实例变量(Instance Variable)
-
定义在类内部的方法之内
- 每个实例对象拥有属于自己的变量副本
- 只能通过实例对象访问
- 用于定义实例对象的个性化特征或状态
例如:
class Person:
species = 'Human' # 类变量
def __init__(self, name):
self.name = name # 实例变量
p1 = Person('John')
p2 = Person('Mary')
print(p1.species) # Human
print(p2.species) # Human
print(p1.name) # John
print(p2.name) # Mary
综上,类变量用于定义类的通用属性,实例变量用于定义实例的独特属性。区分二者是理解Python面向对象的关键。
创建¶
class Employee:
'所有员工的基类'
empCount = 0 # 类变量
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
类函数必有参数 ‘self’¶
必须有一个额外的第一个参数名称, 按照惯例它的名称是 self,self 不是 python 关键字,换成其他词语也行。
创建实例对象与访问¶
继承¶
通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
继承语法 class 派生类名(基类名)
调用基类¶
调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数 ,这点在代码上的区别如下:
class Base:
def base_method(self):
print("Base method")
class Derived(Base):
def derived_method(self):
# 调用基类方法要加类名前缀
Base.base_method(self)
# 调用普通函数
print("Hello")
d = Derived()
d.derived_method()
# 输出
Base method
Hello
在Derived类中:
-
调用Base基类的方法base_method(),需要写成Base.base_method(self)
-
调用普通函数print(),直接写函数名即可
区别在于:
- 调用基类方法需要指明方法所属的基类
- 基类方法需要传入self,指代实例自己
而对于普通函数,只需要直接调用即可,不需要self参数。
这与Python的名称空间和面向对象实现有关,是理解Python类继承的关键点。
运算符重载¶
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
+=¶
在Python中可以通过特殊方法__iadd__来对+=符号进行重载。
__iadd__需要定义在类中,用于指定+=操作时的具体行为。例如:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __iadd__(self, other):
self.x += other.x
self.y += other.y
return self
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v1 += v2
print(v1.x, v1.y) # 4, 6
这里我们定义了__iadd__方法,用于实现两个Vector对象使用+=时的相加操作。
__iadd__方法的参数是另一个要相加的对象,在方法内部我们实现了两个向量的分量相加,并返回self作为结果。这样就实现了+=的运算符重载。
此外,Python还提供了__add__特殊方法用于重载+符号,但是__iadd__和__add__有以下区别:
- __add__返回一个新的对象,不改变原有对象。
- __iadd__在原有对象的基础上进行操作,并返回对原对象的引用。
所以对可变对象进行+=操作时,通常需要实现__iadd__方法。