定义类#
同函数定义(def 语句)类似,类的定义通过 class 语句实现:
class ClassName:
"""类的文档字符串""" # 类的帮助信息
statement # 类体
- 其中
ClassName用于指定类名,一般使用“驼峰式命名法”; """类的文档字符串"""可以通过ClassName.__doc__查看;statement主要由类变量(或称类成员)、方法和属性等定义语句组成。
示例:
class Student:
"""所有学生的基类"""
count = 0 # 类变量,表示学生总数
def __init__(self, id, name): # 特殊的构造方法
self.id = id
self.name = name
self.scores = {}
Student.count += 1
def set_score(self, course, score): # 方法
self.scores[course] = score
上页代码中:
count变量是一个类变量,又称类属性,类变量定义在类中且在函数体之外,它的值将在这个类的所有实例之间共享。类属性可以通过类名称(如Student.count)或实例名访问。__init__和set_score这些在类中定义的函数,称为方法,方法是从属于对象的函数。self是方法的一个特殊参数,代表类的实例,它在方法的参数列表中首先给出,但在调用时不必传入相应的参数。id、name和scores这种使用self.name形式赋值的变量称为实例变量,又称实例属性,一般应该在__init__()函数中定义所有实例变量。- 所有这些类变量、实例变量、方法都可统称为属性(Attribute)。
可以通过属性引用的方式(obj.name)访问类变量,如下所示:
print(Student.count) # 0
创建类的实例#
定义好的类相当于一栋房屋的设计图,它告诉我们房屋的模型,但本身不是房屋。要创建真实的房屋,需要把类实例化。
类的实例化使用函数表示法。如下所示:
class MyClass: # 定义 MyClass 类
pass
obj1 = MyClass() # MyClass 类的实例化
obj2 = MyClass() # MyClass 类的实例化
obj1 = MyClass() 创建类 MyClass 的新实例并将其赋值给变量 obj1。
__init__() 方法是一种特殊的方法,称为构造函数或构造器。每当创建一个类的新实例时,都会自动执行该方法。该方法必须包含一个 self 参数,且其必须是第一个参数。示例如下:
class Dog:
def __init__(self):
print('汪!汪!')
my_dog = Dog() # 汪!汪!
说明
在 __init__() 方法的名称中,开头和结尾处是两个下划线(中间没有空格),这是一种约定,旨在区分 Python 的默认方法和普通方法。
zhangsan = Student(2001, '张三')
lisi = Student(2002, '李四')
print(Student.count)
访问属性#
在创建了类的实例后,可以通过属性引用访问实例的属性(实例变量和方法)。例如:
zhangsan = Student(2001, '张三')
zhangsan.set_score('数学', 79.0) # 调用实例方法时不必给定 self 参数
print(zhangsan.scores) # 访问其 scores 数据属性,{'数学': 79.0}
print(zhangsan.count) # 甚至可以通过实例访问类变量,1
lisi = Student(2002, '李四')
lisi.set_score('数学', 88.5)
print(lisi.name) # 李四
print(lisi.count) # 2
print(Student.count) # 2
类属性、实例属性都可以自由地添加、修改和删除:
class Dog:
bark_mode = '汪!汪!'
def __init__(self):
print(Dog.bark_mode)
my_dog1 = Dog() # 汪!汪!
Dog.bark_mode = '嗷...呜...'
my_dog2 = Dog() # 嗷...呜...
Dog.name = '狗狗'
print(Dog.name) # 狗狗
my_dog1.name = '阿黄'
print(my_dog1.name) # 阿黄,同样的属性名称同时出现在实例和类中,则属性查找会优先选择实例
del Dog.bark_mode
del my_dog1.name
一般来说,实例变量用于每个实例的唯一数据,而类变量用于类的所有实例共享的属性和方法。
也可以使用以下函数的方式来访问属性:
getattr(object, name, /)或getattr(object, name, default, /): 返回object对象的name属性,等价于object.name。hasattr(object, name, /):检查是否存在一个属性,如果字符串name是对象object的属性之一的名称,则返回True,否则返回False。setattr(object, name, value, /):设置一个属性。如果属性不存在,会创建一个新属性,等价于object.name = value。delattr(object, name, /):删除属性,等价于del object.name。
内置属性#
所有类具有一些内置属性:
__dict__: 类的属性(包含一个字典,由类的数据属性组成)。__doc__:类的文档字符串。__name__:类名。__module__:类定义所在的模块(类的全名是__main__.ClassName,如果类位于一个导入模块mymod中,那么ClassName.__module__等于mymod)。__bases__:类的所有父类构成元素(包含了一个由所有父类组成的元组)。
访问限制#
为了保证类内部的某些属性或方法不被外部所访问,可以在属性或方法名前面添加双下划线 __private_attrs 声明该属性为私有,只允许定义这个类本身进行访问。如下所示:
class Student:
"""所有学生的基类"""
__count = 0 # 私有类变量,表示学生总数
def __init__(self, id, name): # 特殊的构造方法
self.__avg_score = None # 私有示例变量
self.id = id
self.name = name
self.scores = {}
Student.__count += 1
def set_score(self, course, score): # 方法
self.scores[course] = score
self.__avg_score = sum(self.scores.values()) / len(self.scores)
def avg_score(self):
return self.__avg_score
zhangsan = Student(2001, '张三')
zhangsan.set_score('数学', 79.0)
print(zhangsan.avg_score())
单下划线、双下划线、头尾双下划线说明:
_foo:以单下划线开头的表示的是保护(protected)类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于from module import *。__foo:以双下划线开头的表示的是私有类型(private)类型的变量,只能是允许这个类本身进行访问。__foo__:头尾双下划线定义的是特殊属性,一般是系统定义名字,类似__init__()之类的。
Python 通过不同的下划线命名方式在一定程度上实现了封装(Encapsulation)。封装是面向对象编程的三大基本特征之一。封装思想保证了类内部数据结构的完整性,使用该类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。