最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Python3萌新入门笔记(27)

Python教程 小楼一夜听春语 4803浏览 0评论

这一篇教程,我们继续学习关于类的相关内容。

五、类的命名空间

模块有命名空间;变量有命名空间;函数有命名空间。

当然,类也会有命名空间。

所有在类中定义的代码都会在独立的命名空间中执行,也就是类的命名空间(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)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (1)

  1. 头像
    class Shielding: # 创建屏蔽类 def __init__(self):===疑问 超帅老师,定义超类时,为什么也要用‘重写超类的init方法’,可否帮忙解答下,感谢 😀
    学习使人进步5年前 (2019-06-26)回复