这一篇教程,我们继续学习关于类的相关内容。
五、类的命名空间
模块有命名空间;变量有命名空间;函数有命名空间。
当然,类也会有命名空间。
所有在类中定义的代码都会在独立的命名空间中执行,也就是类的命名空间(class namespace)。
这个命名空间,可以由类的所有成员(类的实例)进行访问。
接下来,我们再通过示例看一下成员(类的实例)对类的访问。
示例代码:
class Register: # 创建注册类 reg_count=0 # 定义计数变量 def register(self): # 定义计数方法 Register.reg_count+=1 # 累加注册数写入计数变量 print('新增1名注册用户,当前注册数量为%d人' % Register.reg_count ) reg1=Register() # 类的实例化 reg1.register() # 调用计数方法,显示输出结果为:新增1名注册用户,当前注册数量为1人。 reg2=Register() # 类的实例化 reg2.register() # 调用计数方法,显示输出结果为:新增1名注册用户,当前注册数量为2人。
在上方代码中,我们在类的里面定义了一个计数变量,这个变量供全体类的成员(类的实例)访问。
每一个实例都可以调用自身的方法对类的计数变量进行访问。
注意,访问类的变量是通过“类名.变量名”进行访问,而不是“self.变量名”进行访问。
类的实例包含类的所有内容,所以,“self.变量”名访问的是实例对象自身的变量,而不是类的变量。
就如同全国人口统计系统(类)会记录人员数量(变量),所以每一个统计员(实例)也会记录人员数量(变量)。
如果每个统计员(实例)进行人口统计时,只是自己(self)做了人员数量(变量)的记录(访问),而没有记录(访问)到全国人口统计系统(类)的人员数量(变量),那么,全国人口统计(类)的人员数量(变量)则不会发生改变。
我们在上方代码的基础上,再加入一些内容。
示例代码:
print(reg1.reg_count) # 示输出结果为:2 print(reg2.reg_count) # 示输出结果为:2
大家能够看到,实例可以直接访问类的变量。
那么,如果在实例中尝试重新绑定类的特性呢?也就是,通过实例对类的变量进行修改。
示例代码:
reg1.reg_count = 0 # 修改变量值 print(reg1.reg_count) # 示输出结果为:0 print(reg2.reg_count) # 示输出结果为:2
上方代码中,我们试图通过实例对类的变量进行修改。
但是,很明显修改后并没有让类的变量发生变化,而是实例自身的变量产生了变化。
这很像之前我们学过的全局变量和同名的局部变量,局部变量会屏蔽全局变量。
为什么会这样?
理解的关键,在于对“绑定”这个词的理解。
绑定实际上是建立名称与值的关系。
我们需要把变量的名称和值分开来说,则很容易理解什么叫绑定。
就拿中国人(类)来说,中国人有一个头发颜色的特性(变量),默认是黑色(变量值)。
就像每一个出生的中国人(实例)头发颜色的特性(变量)都是黑色(变量值)一样,默认情况下,每一个实例变量的值绑定的是类变量的值。
那么,像刚才我们通过一个实例试图对类变量进行修改,实际上是将实例的变量绑定到了一个新值,其他实例变量的值并不会受到影响,绑定的仍然是类变量的值。
这就像某一个中国人(实例)将自己头发颜色(变量)染(重绑定)成了黄色(变量值),其它中国人(实例)的头发颜色(变量)仍然是黑色(类变量值),并不会一起改变。
绑定示意图:
六、继承(Inheritance)
还是以人类举例,还可以细分为白种人类、黄种人类、黑种人类和棕色人类。
人类是所有人的集合,这些细分的类是人类的子集。
所以,当一个对象所属的类是另一个对象所属的类的子集时,它就是后者的子类(subclass),而后者是前者的超类(superclass),或叫做父类、基类。
在面向对象的程序设计中,子类的关系是隐藏的。
简单来说,类的定义取决于它的所有支持的方法。
类的对象都会包含这些方法。
那么,子类也会包含超类中的这些方法(但是看不到)。
定义子类要做的只是定义更多特性的过程或者重写(override)超类中已有的特性。
我们来看一段代码。
示例代码:
class Shielding: # 创建屏蔽类 def __init__(self): self.words = [] # 屏蔽内容列表 self.symbol = '' # 屏蔽后显示的符号 def change(self, sentence): # 定义修改屏蔽内容的方法 string = sentence for word in self.words: # 遍历屏蔽词列表 if word in sentence: # 判断句子中是否包含屏蔽词 string = string.replace(word, self.symbol * len(word)) # 将句子中的屏蔽内容替换为符号 return string # 返回修改结果 class ShieldingWords(Shielding): # 创建屏蔽词类 def __init__(self): # 重写超类的init方法 self.words = ['银行', '账号', '密码'] # 设置屏蔽词列表 self.symbol = '*' class ShieldingSymbols(Shielding): # 创建屏蔽字符类 def __init__(self): # 重写超类的init方法 self.words = '@' # 设置屏蔽字符列表 self.symbol = '#' def message(self): print('禁止在邮箱地址中使用"%s",已使用"%s"代替!' % (self.words ,self.symbol)) s = Shielding() print(s.change('你银行的账号和密码是什么?')) # 显示输出结果为:你银行的账号和密码是什么? w = ShieldingWords() print(w.change('你银行的账号和密码是什么?')) # 显示输出结果为:你**的**和**是什么? c = ShieldingSymbols() print(c.change('我的邮箱是4907442@qq.com')) # 显示输出结果为:我的邮箱是4907442#qq.com c.message() # # 显示输出结果为:禁止在邮箱地址中使用"@",已使用"#"代替!
代码有些长,不过通过注释应该非常容易读懂。
这里我们创建了1个超类(Shielding)和2个子类(ShieldingWords和ShieldingSymbols)。
超类和子类怎么区分呢?
很简单,在子类名称后方的括号中所写的名称就是超类的名称。
接下来,再来观察。
在超类Shielding中,我们定义了2个方法。
这里值得一提的是init()这个方法,它是无需调用自动执行的方法,所以在下方代码中我们看不到这个方法的调用。
另外一个方法是替换原有词语为符号的方法,这个方法对类的两个特性words和symbol进行了操作。
大家能够看到,在超类Shielding中的这两个方法,实际上是无法完成词语屏蔽的,通过实例化的对象s,调用change()方法,传入的字符串没有任何变化的被输出了。
而两个子类都对init()方法进行了重写,修改了特性的值。
然后,虽然两个子类都没有定义change()这个方法,但是能够正常调用,并输出了修改后的内容。
并且,在子类ShieldingSymbols中我们额外增加了一个message()方法。
通过这段示例代码,我们做个总结:
- 子类包含父类的所有特性;
- 子类中能够对超类的特性进行重写;
- 子类能够添加父类中不存在的特性。
七、查验继承关系
假如我们使用了别人写的代码,怎么知道代码中的某一个类是不是另外一个类的子类或超类呢?
我们可以使用issubclass(class, classinfo)函数。
这个函数能够检查参数cls是否符合参数classinfo类型,或者说前者是否后者的子类。
例如检查上面代码中类的关系。
示例代码:
print(issubclass(ShieldingWords,Shielding)) # 显示输出结果为:True print(issubclass(Shielding,ShieldingWords)) # 显示输出结果为:False
上面的代码是检查两个类的关系。
那么,如果只有一个类,如何知道谁是它的超类?
我们可以使用类的__bases__特性来查看。
示例代码:
print(ShieldingWords.__bases__) # 显示输出结果为:(<class '__main__.Shielding'>,)
还有,如果想知道某个对象是哪个类的实例,可以调用__class__特性。
示例代码:
s = ShieldingWords() print(s.__class__) # 显示输出结果为:<class '__main__.ShieldingWords'>
除此之外,我们还可以使用isinstance()函数来检查一个对象是不是某一个类的实例。
但是,不推荐使用这种方法,因为不符合多态的原则(多态在后边会学到)。
示例代码:
s = ShieldingWords() print(isinstance(s,ShieldingWords))# 显示输出结果为:True print(isinstance(s,Shielding))# 显示输出结果为:True print(isinstance(s,ShieldingSymbols))# 显示输出结果为:False
大家能够看到对象s是子类ShieldingWords的实例,同时也是超类Shielding的实例,但不是子类ShieldingSymbols的实例。
本节知识点:
1、类的命名空间
2、继承
3、查验继承关系
本节英文单词与中文释义:
1、inheritance:继承
2、classinfo:类型
3、variable:变量
4、register:注册
5、sentence:句子
6、shielding:屏蔽
7、word:单词
8、symbols:符号
9、subclass:子类
10、superclass:超类
转载请注明:魔力Python » Python3萌新入门笔记(27)