Python 类介绍,以及定义和使用 Python 类

我被代码海扁署名-非商业-禁演绎
阅读 13:37·字数 4090·更新 
Bilibili 空间
关注 960

前提

阅读本节的前提是已经掌握类的相关概念,你可以查看编程教程面向对象编程,类,实例介绍一节来了解他们。

定义 Python 类

在 Python 中,类通常被定义在模块中,其语法的基本形式如下。

class <classname>:
    <docstring>
    <block>

classname 部分

classname为 Python 类的名称,他需要符合 Python 的标识符规范,不能使用关键字或保留关键字。

docstring 部分

docstring是 Python 类的文档字符串,包含了对类的说明,这并非强制性的要求,一个 Python 类可以没有文档字符串。

block 部分

block为 Python 类的主体代码,他和docstring都需要使用某种空白字符进行缩进,以表示其归属于 Python 类。

Python 类的特性

与模块类似,在 Python 类中定义的变量(字段),属性,方法(函数)等内容,被称为特性(Attribute)。特性可通过形式类似于c.namec.name=value的表达式进行访问,其中c为 Python 类或对象(类的实例),name为特性(名称,标识符),value为特性的新值。

当然,Python 类的特性可以被称呼为变量,方法,属性,这并没有什么问题。

下面是一个简单的 Python 类Apple,包含变量和静态方法。

apple.py
# 一个简单的类 Apple
class Apple:
	# 变量 variety
	variety = '普通苹果'
	# 静态方法 show
	@staticmethod
	def show():
		print(Apple.variety)

# 为特性 variety 赋值 Apple.variety = '石头苹果' # 调用 show 方法 Apple.show()
石头苹果

Python 的类特性和实例特性

在 Python 中,类的特性分为类特性和实例特性,类特性直接在 Python 类中定义,或通过表示类的参数(一般约定为cls)来定义,而实例特性则需要通过 Python 实例,或表示实例的参数(一般约定为self)来定义。

Python 类特性可通过类或表示类的参数(一般约定为cls),以及 Python 实例或表示实例的参数(一般约定为self)来访问,而 Python 实例特性则只能通过实例或表示实例的参数来访问。

为 Python 类或实例添加暂时特性

在没有限制的情况下,一个 Python 类或实例可以添加暂时存在的特性,只需要使用形式为c.name=value的表达式即可,其中c为类或实例,name为添加的特性(名称,标识符),value为特性的值。

如何查看 Python 类或实例的所有特性?

通过 Python 类,实例,对象的特殊特性__dict__,你可以查看其对应的所有特性,包括私有特性和暂时特性在内。__dict__是一个字典对象,其中键值对的键表示特性的名称,键值对的值表示特性的具体内容。

需要指出的是,Python 类的__dict__与实例的__dict__中的键值对不会重叠,类的__dict__仅包含类特性,实例的__dict__仅包含实例特性,不过,不排除存在分别归属于 Python 类和实例的同名特性。

我们调整之前的示例,为类Apple添加构造器以定义实例变量weight,并通过类添加暂时类变量price,通过实例添加暂时实例变量price,然后输出显示Apple类和实例的__dict__特性。

apple.py
# 一个简单的类 Apple
class Apple:
	# …
	# 构造器
	def __init__(self, w):
		# 通过表示实例的 self 定义了实例变量 weight
		self.weight = w
# …
# 为 Apple 类添加一个类变量,然后显示 Apple 类的所有特性
Apple.price = 10
print(Apple.__dict__)
# 为实例添加一个实例变量,然后显示实例的所有特性
apple = Apple(100)
apple.price = 30
print(apple.__dict__)
{'__module__': '__main__', 'variety': '石头苹果', 'show': <staticmethod(<function Apple.show at >)>, '__init__': <function Apple.__init__ at >, '__dict__': <attribute '__dict__' of 'Apple' objects>, '__weakref__': <attribute '__weakref__' of 'Apple' objects>, '__doc__': None, 'price': 10}
{'weight': 100, 'price': 30}

不能通过 Python 实例来直接赋值修改类特性

你可以通过 Python 实例或表示实例的参数(比如self)来读取类特性,但无法进行赋值操作,因为赋值操作将被认为是向 Python 实例增加新的特性,这类似于试图在函数中直接赋值模块定义的变量。

在下面的代码中,书写apple.variety等同于读取Apple.variety,书写apple.variety='超大苹果'等同于为实例apple添加实例变量varietyApple.variety不会被修改。

apple.py
# …
# 创建 Apple 类的实例
apple = Apple(30)
# 通过实例访问类变量 variety
print(apple.variety)

# 下面的赋值语句将为实例定义新的实例变量 variety apple.variety = '超大苹果' # 因此,类变量 variety 并没有变化 print(Apple.variety)
石头苹果
石头苹果

定义 Python 类的变量

Python 类的变量(字段)分为类变量和实例变量,他是 Python 类的特性之一,你可以通过以下形式来定义类变量或实例变量,其中,cls为表示 Python 类的参数,self为表示 Python 实例的参数。

[cls|self.]<variablename>=<value>

variablename 部分

variablename为变量名称,他需要符合 Python 的标识符规范,不能使用 Python 关键字或保留关键字。

value 部分

value为变量对应的值。

student.py
# 一个表示学生的类 Student
class Student:
	# 类变量 count
	count = 0
	# 构造器
	def __init__(self, n, a):
		# 实例变量 name,age
		self.name = n
		self.age = a

定义 Python 类的方法

Python 类的方法(函数)是类的特性之一,他与 Python 模块中的函数有相似之处,可通过如下形式进行定义,其中,@classmethod表示定义类方法,@staticmethod表示定义静态方法。

[@classmethod|@staticmethod]
def <methname>(<parameterlist>)
    <block>

methname 部分

methname为方法名称,他需要符合 Python 的标识符规范,不能使用 Python 关键字或保留关键字。

parameterlist 部分

parameterlist是方法的参数列表,他定义了方法的所有参数,参数之间使用,进行分隔。

block 部分

block为方法的主体代码,需要使用某种空白字符进行缩进,以表示其归属于方法。

如果未指定修饰符@classmethod@staticmethod,则定义的方法被称为实例方法,其第一个参数一般命名为self,表示 Python 实例本身,通过该参数可读取写入实例特性,或读取类特性。当通过 Python 实例调用实例方法时,需要省去self参数,当通过 Python 类调用实例方法时,需要给出self参数。

如果指定了修饰符@classmethod,则定义的方法为类方法,其第一个参数一般命名为cls,表示 Python 类本身,通过该参数可以访问类特性,但不能访问实例特性。无论是通过 Python 实例还是 Python 类,调用类方法时都需要省去cls参数。

如果指定了修饰符@staticmethod,则定义的方法为静态方法,静态方法不像实例方法或类方法一样拥有特殊参数,因此他不能通过特殊参数来访问 Python 实例特性或类特性。

直接定义在 Python 类中的方法均为类特性

事实上,直接定义在 Python 类中的方法均为类特性,而非实例特性,无论这些方法被称为实例方法,类方法还是静态方法,他们之间的主要区别在于,首个参数表示的是 Python 实例还是 Python 类,或均不表示。

也正因为都是类特性,实例方法,类方法,静态方法既可以通过 Python 实例调用,也可以通过 Python 类调用。

函数

想要深入了解 Python 函数,你可以查看Python 函数,参数,返回值介绍,以及 Python 函数的定义和调用一节。

下面,我们为之前的Student类增加一些方法,并分别通过类或实例来调用他们。

student.py
# 一个表示学生的类 Student
class Student:
	# …
	# 实例方法 info
	def info(self):
		print(f'{self.name} {self.age}')

# 类方法 show @classmethod def show(cls): # 通过参数 cls 读取类变量 count print(f'一共 {cls.count} 个学生') # 静态方法 set_count @staticmethod def set_count(c): # 只能通过类访问类变量 Student.count = c print(f'学生数量被设置为 {Student.count}')
student = Student('小小', 13) # 调用实例方法 info student.info() Student.info(student) # 调用静态方法 set_count student.set_count(-100) Student.set_count(100) # 调用类方法 show student.show() Student.show()
小小 13
小小 13
学生数量被设置为 -100
学生数量被设置为 100
一共 100 个学生
一共 100 个学生

定义 Python 类的私有特性

无论是 Python 类特性还是实例特性,如果标识符以__开头,则这些特性即为私有特性,只能在定义他们的 Python 类中访问,不能在外部或派生类中访问。

Python 类的私有特性标识符会自动增加前缀

__开头的私有特性,其标识符会自动增加特定前缀,其内容为_与类名称的组合,这一现象可通过 Python 类或 Python 实例的__dict__特性来观察。标识符的改动仅涉及定义特性的类,这也就是无法在外部或派生类中使用私有特性的原因,因为你在访问一个并不存在的内容。

当然,在了解以上规则后,私有特性可能变得不再私有,只需要采用具有特定前缀的标识符进行访问即可。

下面的类Teacher定义了两个私有的实例变量,他们的标识符自动添加了前缀_Teacher

teacher.py
# 一个表示教师的类 Teacher
class Teacher:
	# 构造器
	def __init__(self, n, a):
		# 私有实例变量 __name,__age
		self.__name = n
		self.__age = a

teacher = Teacher('隐者', 30) # 显示 Teacher 实例的所有特性 print(teacher.__dict__) # 使用特殊方式访问私有变量 __name print(teacher._Teacher__name)
{'_Teacher__name': '隐者', '_Teacher__age': 30}
隐者

定义 Python 类的构造器

Python 类的构造器是一个名为__init__的实例方法,与其他实例方法一样,__init__方法的第一个参数一般命名为self,表示 Python 实例自身,其余参数可用于初始化实例变量或执行其他操作,就如同Student类所作的那样。

当然,在 Python 的官方文档中,并没有构造器这样的说法,__init__的含义仅为初始化,他在 Python 实例创建后被调用。

创建 Python 类的实例

要创建 Python 类的实例,你需要使用类名称和()()包含了一组参数,这些参数一般与__init__方法的参数一致(需要省去self)。比如,之前示例中使用Student('小小',13)创建了Student类的实例。

如何查看 Python 实例对应的类型?

通过 Python 实例(对象)的__class__属性(Property),可以获取该实例对应的类型(类)信息,__class__属性的返回值是一个type对象。

对于已定义的 Python 类来说,__class__属性的返回值显示为<class 'type'>,这表示已定义的 Python 类可被视为实例,其类型是type

student.py
# …
# 获取 Student 类和之前创建的实例 student 的类型信息
print(student.__class__)
print(Student.__class__)
<class '__main__.Student'>
<class 'type'>

Python 类的命名空间

理所当然的,Python 类应该拥有自己的命名空间,以避免类所拥有的特性的标识符与其他标识符冲突。

命名空间,作用域

想要深入了解命名空间和作用域,你可以查看编程教程命名空间,作用域介绍一节。

Python 类的文档字符串

与 Python 函数,模块类似,Python 类也具有存储在__doc__中的文档字符串,他是字符串字面量,是类的第一行有效代码,可以采用紧密相邻或加入空白的方式进行拼接,不包含需要运算的内容或操作。

hello.py
# 一个奇怪的类
class Hello:
	"""你好啊,"""'Python!'

Python 嵌套类

嵌套类是定义在另一个类,函数或方法中的 Python 类。由于作用域的一般性原则,被定义的嵌套类的可访问性,等同于同一命名空间中定义的 Python 变量。

下面定义的嵌套类World,其可访问性等同于Hello中的类变量。

hello.py
# 一个奇怪的类
class Hello:
	# …
	# 一个奇怪的嵌套类
	class World:
		pass

内容分类

源码

src/zh/classes·codebeatme/python·GitHub