5. 类与对象
类是创建对象的模板。对象被称为类的实例。
5.1. 一个对象类
程序 (classes_01)
| # -*- coding=utf-8 -*-
class Objet:
"""une classe Objet vide"""
# any variable can have attributes by construction
obj1=Objet()
obj1.attr1="un"
obj1.attr2=100
# displays the
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# modify object
obj1.attr2+=100
# displays the
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# assigns object1 reference to object2
obj2=obj1
# modify obj2
obj2.attr2=0
# displays both objects
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
print "objet2=[{0},{1}]".format(obj2.attr1,obj2.attr2)
|
注:
- 第 4 行:另一种形式的注释。以三个 """ 开头,可跨多行;
- 第3-4行:一个空对象类;
- 第7行:Object类的实例化;
- 第17行:引用复制。变量obj1和obj2是指向同一个对象的两个指针(引用)。
结果
| objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
|
5.2. Person 类
程序 (classes_02)
| # -*- coding=utf-8 -*-
class Personne:
# class attributes
# undeclared - can be created dynamically
# method
def identite(self):
# a priori, uses non-existent attributes
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# attributes are public and can be created dynamically
p=Personne()
p.prenom="Paul"
p.nom="Langevin"
p.age=48
# method call
print "personne={0}\n".format(p.identite())
|
注:
- 第 3-10 行:包含方法的类;
- 第8行:类中的每个方法都必须将
self对象(指当前对象)作为其第一个参数。
结果
personne=[Paul,Langevin,48]
5.3. 带有构造函数的 Person 类
程序 (classes_03)
| # -*- coding=utf-8 -*-
class Personne:
# manufacturer
def __init__(self,prenom,nom,age):
self.prenom=prenom;
self.nom=nom;
self.age=age;
# method
def identite(self):
# a priori, uses non-existent attributes
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
p=Personne("Paul","Langevin",48)
# method call
print "personne={0}\n".format(p.identite())
|
注:
- 第 6 行:类的构造函数名为 __init__。与其他方法一样,其第一个参数是 self;
- 第 18 行:使用类构造函数创建了一个 Person 对象。
结果
personne=[Paul,Langevin,48]
5.4. 在构造函数中包含有效性检查的Person类
程序 (classes_04)
| # -*- coding=utf-8 -*-
import re
# -------------------
# a proprietary exception class
class MyError(Exception):
pass
class Personne:
# manufacturer
def __init__(self,prenom="x",nom="x",age=0):
# first name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",prenom)
if not match:
raise MyError("Le prenom ne peut etre vide")
else:
self.prenom=match.groups()[0]
# name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",nom)
if not match:
raise MyError("Le nom ne peut etre vide")
else:
self.nom=match.groups()[0]
# age must be valid
match=re.match(r"^\s*(\d+)\s*$",str(age))
if not match:
raise MyError("l'age doit etre un entier positif")
else:
self.age=match.groups()[0]
def __str__(self):
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
try:
p=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# another object Nobody
try:
p=Personne(" xx "," yy "," zz")
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# another person
try:
p=Personne()
print "personne={0}".format(p)
except MyError, erreur:
print erreur
|
注:
- 第 7-8 行:一个从 Exception 类派生的 MyError 类。它并未为后者添加任何功能,仅用于提供自定义异常;
- 第 13 行:构造函数的参数具有默认值。因此,操作 p = Person() 等同于 p = Person("x", "x", 0);
- 第 15–19 行:检查 first_name 参数。该参数不能为空。若为空,则抛出 MyError 异常并附带错误信息;
- 第 21–25 行:last_name 参数的检查同上;
- 第 27–31 行:年龄验证;
- 第 33–34 行:__str__ 函数取代了之前名为 identite 的方法;
- 第 38–42 行:实例化 Person 对象并显示其身份信息;
- 第 39 行:实例化;
- 第 40 行:显示。该操作需要将人 p 作为字符串显示。如果该方法存在,Python 解释器会自动调用 p.__str__() 方法。该方法的作用与 Java 或 .NET 语言中的 toString() 方法相同;
- 第 41–42 行:处理可能抛出的 MyError 异常,并显示与该异常相关的错误信息;
- 第 44–48 行:与上述操作相同,但针对使用错误参数创建的第二个 Person 实例;
- 第 50–54 行:与上述情况相同,针对使用默认参数实例化的第三个 Person 对象。
结果
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[x,x,0]
|
5.5. 添加一个充当第二个构造函数的方法
程序 (classes_05)
| # -*- coding=utf-8 -*-
import re
# -------------------
# a proprietary exception class
class MyError(Exception):
pass
class Personne:
# class attributes
# undeclared - can be created dynamically
# manufacturer
def __init__(self,prenom="x",nom="x",age=0):
# first name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",prenom)
if not match:
raise MyError("Le prenom ne peut etre vide")
else:
self.prenom=match.groups()[0]
# name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",nom)
if not match:
raise MyError("Le nom ne peut etre vide")
else:
self.nom=match.groups()[0]
# age must be valid
match=re.match(r"^\s*(\d+)\s*$",str(age))
if not match:
raise MyError("l'age doit etre un entier positif")
else:
self.age=match.groups()[0]
def initWithPersonne(self,p):
# initializes the current object with a person p
self.__init__(p.prenom,p.nom,p.age)
def __str__(self):
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
try:
p0=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p0)
except MyError, erreur:
print erreur
# another object Nobody
try:
p1=Personne(" xx "," yy "," zz")
print "personne={0}".format(p1)
except MyError, erreur:
print erreur
# another person
p2=Personne()
try:
p2.initWithPersonne(p0)
print "personne={0}".format(p2)
except MyError, erreur:
print erreur
|
注:
- 与之前的脚本相比,区别在于第35至37行。我们添加了 initWithPerson 方法。该方法会调用 __init__ 构造函数。与类型化语言不同,这里无法通过参数或返回值的性质来区分同名方法。因此,无法定义多个构造函数来根据不同的参数(在本例中是 Person 类型的对象)创建对象。
结果
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[Paul,Langevin,48]
|
5.6. 一个 Person 对象的列表
程序 (classes_06)
| # -*- coding=utf-8 -*-
class Personne:
...
# ---------------------------------- main
# create a list of person objects
groupe=[Personne("Paul","Langevin",48), Personne("Sylvie","Lefur",70)]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
注:
结果
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]
5.7. 创建一个从 Person 类派生的类
程序 (classes_07)
| # -*- coding=utf-8 -*-
import re
class Personne:
...
class Enseignant(Personne):
def __init__(self,prenom="x",nom="x",age=0,discipline="x"):
Personne.__init__(self,prenom,nom,age)
self.discipline=discipline
def __str__(self):
return "[{0},{1},{2},{3}]".format(self.prenom,self.nom,self.age,self.discipline)
# ---------------------------------- main
# create a list of Personne objects and derivatives
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70)]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
注:
- 第5-6行:Person类已定义;
- 第 8 行:声明 Teacher 类为 Person 类的子类;
- 第 10 行:派生类 Teacher 的构造函数必须调用父类 Person 的构造函数;
- 第 21-22 行:为了显示 group[i],解释器使用了方法 group[i].__str__()。所使用的 __str__() 方法是 group[i] 的实际类的该方法,如下所示。
结果
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
5.8. 创建一个从 Person 类派生的第二个类
程序 (classes_08)
| # -*- coding=utf-8 -*-
import re
class Personne:
...
class Enseignant(Personne):
...
class Etudiant(Personne):
def __init__(self,prenom="x",nom="x",age=0,formation="x"):
Personne.__init__(self,prenom,nom,age)
self.formation=formation
def __str__(self):
return "[{0},{1},{2},{3}]".format(self.prenom,self.nom,self.age,self.formation)
# ---------------------------------- main
# create a list of Personne objects and derivatives
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70), Etudiant("Steve","Boer",22,"iup2 qualite")]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
注:
结果
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[Steve,Boer,22,iup2 qualite]