Python面向对象类编写细节分析【类,方法,继承,超类,接口等】
作者:KLeonard 发布时间:2023-01-01 11:23:13
本文实例讲述了Python面向对象类编写技术细节。分享给大家供大家参考,具体如下:
类代码编写细节
继续学习类、方法和继承。
class语句
以下是class语句的一般形式:
class <name>(superclass,...):
data = value
def method(self,...):
self.member = value
在class语句内,任何赋值语句都会产生类属性,而且还有特殊名称方法重载运算符。例如,名为__init__
的函数会在实例对象构造时调用(如果定义过的话)。
例子
类是命名空间,也就是定义变量名(属性)的工具。
1.就像函数一样,class语句是本地作用域,由内嵌的赋值语句建立的变量名,就存在于这个本地作用域内。
2.就像模块内的变量名,在class语句内赋值的变量名会变成类对象中的属性。
因为class是复合语句,所以任何种类的语句都可位于其主体内:print、=、if、def等。当class语句自身执行时,class语句内的所有语句都会执行。在class语句内赋值的变量名,会创建类属性,而内嵌的def则会创建类方法。
例如,把简单的非函数的对象赋值给类属性,就会产生数据属性,由所有实例共享。
>>> class ShareData:
spam = 42
>>> x = ShareData()
>>> y = ShareData()
>>> x.spam,y.spam
(42, 42)
在这里,因为变量名spam是在class语句的顶层进行赋值的,因此会附加在这个类中,从而为所有的实例共享。我们可通过类名称修改它,或者是通过实例或类引用它。
>>> ShareData.spam = 99
>>> x.spam,y.spam,ShareData.spam
(99, 99, 99)
这种类属性可以用于管理贯穿所有实例的信息。例如,所产生的实例的数目的计数器。
现在,如果通过实例而不是类来给变量名spam赋值时,看看会发生什么:
>>> x.spam = 88
>>> x.spam,y.spam,ShareData.spam
(88, 99, 99)
对实例的属性进行赋值运算会在该实例内创建或修改变量名,而不是在共享的类中。
对对象属性进行赋值总是会修改该对象,除此之外没有其他的影响。例如,y.spam
会通过继承而在类中查找,但是,对x.spam
进行赋值运算则会把该变量名附加在x本身上。
看下面这个例子,可以更容易理解这种行为,把相同的变量名储存在两个位置:
>>> class MixedNames:
data = 'spam'
def __init__(self,value):
self.data = value
def display(self):
print(self.data,MixedNames.data)
当创建这个类的实例的时候,变量名data会在构造函数方法内对self.data
进行赋值运算,从而把data附加到这些实例上。
>>> x = MixedNames(1)
>>> y = MixedNames(2)
>>> x.display(),y.display()
1 spam
2 spam
(None, None)
【这里的(None,None)是调用display函数的返回值】
结果就是,data存在于两个地方:在实例对象内(由__init__
中的self.data
赋值运算所创建)以及在实例继承变量名的类中(由类中的data赋值运算所创建)。类的display方法打印了这两个版本,先以点号运算得到self实例的属性,然后才是类。
利用这些技术把属性储存在不同对象内,我们可以决定其可见范围。附加在类上时,变量名是共享的;附加在实例上时,变量名是属于每个实例的数据,而不是共享的数据。
方法
方法即函数。方法在class中是由def语句创建的函数对象。从抽象的角度来看,方法替实例对象提供了要继承的行为。从程序的角度看,方法与简单函数的工作方式完全一致,只是有一个重要的差别:方法的第一个参数总是接收方法调用的隐性主体,也就是实例对象。
Python会自动把实例方法的调用对应到类方法函数。如下所示,方法调用需要通过实例,就像这样:
instance.method(args...)
这会自动翻译成以下形式的类方法函数调用:
class.method(instance,args...)
class通过Python继承搜索流程找出方法名称所在之处。事实上,两种调用形式在Python中都有效。
在类方法中,按惯例第一个参数通常都称为self(严格来说,只有其位置重要,而不是它的名称)。这个参数给方法提供了一个钩子,从而返回调用的主体,也就是实例对象:因为类可以产生许多实例对象,所以需要这个参数来惯例每个实例彼此各不相同的数据。
例子
定义下面这个类:
>>> class NextClass:
def printer(self,text):
self.message = text
print(self.message)
我们通过实例调用printer方法如下:
>>> x = NextClass()
>>> x.printer('instance call')
instance call
>>> x.message
'instance call'
当通过实例进行点号运算调用它时,printer会先通过继承将其定位,然后它的self参数会自动赋值为实例对象(x)。text参数会获得在调用时传入的字符串('instance call')。注意:因为Python会自动传递第一个参数给self,实际上只需要传递一个参数。在printer中,变量名self是用于读取或设置每个实例的数据的,因为self引用的是当前正在处理的实例。
方法能通过实例或类本身两种方法其中的任意一种进行调用。例如,我们也可以通过类的名称调用printer,只要明确地传递了一个实例给self参数。
>>> NextClass.printer(x,'class call')#Direct Class Call
class call
>>> x.message
'class call'
通过实例和类的调用具有相同的效果,只要在类形式中传递了相同的实例对象。实际上,在默认情况下,如果尝试不带任何实例调用的方法时,就会得到出错信息。
>>> NextClass.printer('bad call')
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
NextClass.printer('bad call')
TypeError: printer() missing 1 required positional argument: 'text'
调用超类构造函数
在构造时,Python会找出并且只调用一个__init__
。如果保证子类的构造函数也会执行超类构造时的逻辑,一般都必须通过类明确地调用超类的__init__
方法。
class Super:
def __init__(self,x):
...default code...
class Sub(Super):
def __init__(self,x,y):
Super.__init__(self,x)
...custom code...
I = Sub(1,2)
这种写法便于维护代码,之前也介绍过。这种方法扩展了超类的方法,而不是完全取代了它。
类接口技术
扩展只是一种与超类接口的方法。下面所示的specialize.py文件定义了多个类,示范了一些常用技巧。
Super:定义一个method函数以及在子类中期待一个动作的delegate。
Inheritor:没有提供任何新的变量名,因此会获得Super中定义的一切内容。
Replacer:用自己的版本覆盖Super的method
Extender:覆盖并回调默认method,从而定制Super的method
Provider:实现Super的delegate方法预期的action方法。
下面是这个文件:
class Super:
def method(self):
print('in Super.methon')
def delegate(self):
self.action()
class Inheritor(Super):
pass
class Replacer(Super):
def method(self):
print('in Replacer.method')
class Extender(Super):
def method(self):
print('starting Extender.method')
Super.method(self)
print('ending Extender.method')
class Provider(Super):
def action(self):
print('in Provider.action')
if __name__=='__main__':
for klass in (Inheritor,Replacer,Extender):
print('\n'+klass.__name__+'...')
klass().method()
print('\nProvider...')
x = Provider()
x.delegate()
执行结果如下:
Inheritor...
in Super.methon
Replacer...
in Replacer.method
Extender...
starting Extender.method
in Super.methon
ending Extender.method
Provider...
in Provider.action
抽象超类
注意上例中的Provider类是如何工作的。当通过Provider实例调用delegate方法时,有两个独立的继承搜索会发生:
1.在最初的x.delegate
的调用中,Python会搜索Provider实例和它上层的对象,直到在Super中找到delegate的方法。实例x会像往常一样传递给这个方法的self参数。
2.在Super.delegate
方法中,self.action
会对self以及它上层的对象启动新的独立继承搜索。因为self指的是Provider实例,在Provider子类中就会找到action方法。
这种“填空式”的代码结构一般就是OOP的软件框架。这个例子中的超类有时也称作是抽象超类——也就是类的部分行为默认是由其子类所提供的。如果预期的方法没有在子类中定义,当继承搜索失败时,Python会引发未定义变量名的异常。
希望本文所述对大家Python程序设计有所帮助。
来源:https://blog.csdn.net/gavin_john/article/details/50704472


猜你喜欢
- CAS 全称集中式认证服务(Central Authentication Service),是实现单点登录(SSO)的一中手段。CAS 的通
- 数模比赛中,常常需要对数据进行处理和分析,但
- 几个方式(本文不作介绍),要将Session保存到SQL Server中,需要有以下几个步骤:1.首先要创建用于保存Session数据的数据
- 下面展示一下非瀑布流的item布局情况,每个item的高度都是一样的,所以 他的index就是左右左右,position所对应的itemVi
- PDOStatement::errorInfoPDOStatement::errorInfo — 获取跟上一次语句句柄操作相关的扩展错误信息
- 1、注册时验证数据库用户名是否存在。 2、输入密码时提示密码强度和验证2次密码输入是否一样。 3、注册时验证数据库联系邮箱是否存在。 4、注
- 1、问题描述在使用v-model指令实现输入框数据双向绑定,输入值时对应的这个变量的值也随着变化;但是这里不允许使用v-model,需要写一
- 前言加密解密在实际开发中应用比较广泛,常用加解密分为:“对称式”、“非对称式&a
- 创作思路:主要还是想尝试做点稍微不同于整天为迎合客户而做的东西.然后闲时就开始构思,比如坐车,走路什么的.看到有一些复古手机的相关图,就想到
- mongodb是基于分布式文件存储的nosql(非关系型)数据库虽说是nosqldb, but mongodb 其中的文档可以是关系型的在m
- ValueError: The number of FixedLocator locations (9), usually from a c
- 一个写给别人的小代码顺便也贴上来这是一个滑动展示用的小容器通过鼠标移动和离开触发滑动效果<!DOCTYPE html PUBLIC &
- 在Flask开发RESTful后端时,前端请求会遇到跨域的问题。下面是解决方法:使用 flask-cors库可以很容易的解决pip inst
- 缺省的情况下GitLab的官方镜像中提供了一个Redis,如果希望把此缓存数据库放在GitLab的容器之外的话需要怎么做呢?这篇文章结合示例
- 本文实例讲述了js获取url传值的方法。分享给大家供大家参考,具体如下:js获取url参数值:index.htm?参数1=数值1&参
- urllib包和http包都是面向HTTP协议的。其中urllib主要用于处理 URL,使用urllib操作URL可以像使用和打开本地文件一
- MySQL中的事件调度器,EVENT,也叫定时任务,类似于Unix crontab或Windows任务调度程序。EVENT由其名称和所在的s
- 条形码和二维码#引入所需要的基本包from reportlab.pdfgen import canvasfrom reportlab.gra
- #squeeze 函数:从数组的形状中删除单维度条目,即把shape中为1的维度去掉#unsqueeze() 是squeeze()的反向操作
- 一扯上文化二字,总觉虚无缥缈、漫无边际,或者老气横秋,如何有趣地利用中华文化的思想和符号,结合现代的元素,使其成为有意思的传播手法,这个问题