一.类概述
作为一门面向对象(Object)的编程语言,Python的核心当然包含类(class)的设计。本文详细介绍了类的方法面面,具体介绍内容包括如下图所示:
二.变量
2.1 类变量
类变量会在所有类实例间共享,类实例还未创建时,类变量就已经存在。类变量在所有方法之外定义,通常是在类头的正下方以及构造函数和其它方法之前。
class People():
class_name = "demo"
def __init__(self):
pass
if __name__ == "__main__":
print(People.class_name)
print(People().class_name)
类变量可以通过类名直接引用,也可以通过类实例来引用。
2.2 类实例变量
类实例变量由类实例所拥有,每个类实例都由自己一套独立的类实例变量。
class People():
class_name = "demo"
def __init__(self, name="", age=1, sex="M") -> None:
self.name = name
self.age = age
self.sex = sex
if __name__ == "__main__":
p = People(name="Tom")
p1 = People(name="Tony")
print(p.name, p1.name)
三.类中的方法
3.1 实例方法
实例方法(instance methods)对由实例变量提供的数据/值执行一系列的操作。实例方法的第一个参数须为self ,它指的是当前对象,用于访问类中的变量和方法。实例方法不在类间共享。下面的示例代码中,__init__ 和print_info 都是类的实例方法。
class People():
def __init__(self, name="", age=1, sex="M") -> None:
self.name = name
self.age = age
self.sex = sex
def print_info(self):
print(f"Name: {self.name}, Age: {self.age}, Sex: {self.sex}")
if __name__ == "__main__":
p = People("Tom", 22, "M")
p.print_info()
3.1.1 类初始化方法
这里着重介绍一下类的初始化方法__init__() ,该方法在类实例创建的时候该方法会被自动调用。
在类的构造方法中,若存在继承关系,可以通过super() 方法来调用父类的初始化方法完成父类属性的初始化。
super() 方法可以返回超类的临时对象,然后可以通过它调用超类的方法。super() 方法可以包含两个参数:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * self.length + 2 * self.width
class Square(Rectangle):
def __init__(self, length):
super(Square, self).__init__(length, length)
Python3中super(Square, self) 的调用等效于无参super() 的调用。
3.1.2 __call__ 方法
Python允许class定义特殊的实例方法__call__ ,通过该方法可以让像调用函数一样调用对象。
from collections import defaultdict
class CountMissing():
def __init__(self):
self.add = 0
def __call__(self):
self.add += 1
return 0
if __name__ == "__main__":
items = {'apple': 3, 'banana': 2}
goods = [('orange', 6), ('watermelon', 1), ('strawberry', 9), ('apple', 8)]
counter = CountMissing()
items = defaultdict(counter, items)
for fruit, num in goods:
items[fruit] += num
print(counter.add)
3.2 类方法
同类变量一样,类方法(class methods)是所有类示例共享的方法。类方法只能访问类变量,而不能访问类实例变量(因为类实例还未创建)。类方法可以通过修改类变量来修改类的状态。
3.2.1 通过@classmethod 装饰器
在Python中,可以使用@classmethod 装饰器来将方法声明为类方法。
class People():
class_name = "demo"
def __init__(self, name="", age=1, sex="M"):
self.name = name
self.age = age
self.sex = sex
@classmethod
def print_info(cls):
print(f"class name: {cls.class_name}")
if __name__ == "__main__":
People.print_info()
People().print_info()
类方法的注意事项包括:
- 第一个参数必须为
cls ; - 类方法仅能访问类变量,例如
class_name ,但不能访问实例属性,例如self.name ; - 既可以通过
类名.方法名 来调用,也可以通过类实例对象.方法名 来调用。
使用@classmethod 的好处:在之后重构类时,不需要修改初始化函数,只需额外添加处理的函数,然后使用@classmethod 即可。
3.2.2 通过classmethod() 方法
Python中还可以通过内置的classmethod(function) 方法来将正常的方法的方法转换为类方法,其中function 便是要转换为类方法的函数名。
class People():
class_name = "demo"
def __init__(self, name="", age=1, sex="M"):
self.name = name
self.age = age
self.sex = sex
def print_info(cls):
print(f"class name: {cls.class_name}")
if __name__ == "__main__":
People.print_info = classmethod(People.print_info)
People().print_info()
3.3 静态方法
静态方法(static methods)与类方法有些相似,它也是绑定在类上,而不是类实例对象上。但静态方法没有像self 和cls 这样的隐式的第一个参数,这意味着它不能访问类变量和类实例变量。静态方法也能通过类名.静态方法名 的方式来调用。
与类方法类似,静态方法通过可以通过@staticmethod 装饰器或内置的staticmethod(function) 方法来定义。
class People():
class_name = "demo"
def __init__(self, name="", age=1, sex="M"):
self.name = name
self.age = age
self.sex = sex
@staticmethod
def temp(x):
print(x)
def temp1(x, y):
print(x + y)
if __name__ == "__main__":
People.temp1 = staticmethod(People.temp1)
People.temp(10)
People.temp1(10, 20)
四.类装饰器
4.1 @property装饰器
Python提供了@property 装饰器,它使得在类中使用getter 和setter 变得容易。一般情况下,只要不将类属性设置为私有属性就可以在类外自由的使用类属性。但是有时候,可能希望在设置属性时进行一些特殊的行为,例如检查设置的值是否大于0。这种情况下,@property 装饰器便能排上用场了,例如:
class Circle():
def __init__(self, radius):
self.radius = radius
@property
def radius(self):
return self.radius
@radius.setter
def radius(self, radius):
if radius <= 0:
raise ValueError(f"Circle's radius must be > 0, but get {radius}")
self.radius = radius
c = Circle(-2)
在该例子中,类初始化传入参数radius=-2 ,在类初始化函数中当执行self.radius = radius 时会自动调用@radius.setter 方法,其检查raduis 的值小于等于0,引发异常。
五.访问权限控制
Python的类同样也有类似Java和C++的访问权限控制,它同样可以分为Public、Protected和Private。
- 公有:默认的方法和成员权限,通过对象的点运算符
. 访问即可直接访问; - 受保护:以单下划线开头
_ ,只能通过类方法和子类本身进行访问。注意,这并非是强制要求,只是希望用户遵循这样的要求。 - 私有:以双下划线
__ 开头,只能通过类方法访问。
class People():
def __init__(self, name, age, id):
self.name = name
self._age = age
self.__id = id
def _protected_mthd(self):
print("Protected")
def __private_mthd(self):
print("Private")
if __name__ == "__main__":
p = People("Tom", 22, "1001")
print(p._age)
p._protected_mthd()
print(p.__id)
p.__private_mthd()
5.1 私有类型的名称转写机制
实际上,Python中并没有禁止访问类中某一成员的保护机制。在外界看来无法访问私有属性的原因并不是因为保护机制,而是类方法使用了名称转写机制,即对于私有属性__X ,其会被转写为_classname__X ,其中classname 为类名(私有方法也类似)。
print(p._People__id)
p._People__private_mthd()
通过上述的名称转写机制,可以避免类继承过程中的命名冲突(子类定义与父类相同名称的属性)。
|