Python一一类代码编写细节

class语句

一般形式

class是复合语句,其缩进语句的主体一般都出现在头一行下边。在头一行中,超类列在类名称之后的括号内,由逗号相隔。列出一个以上的超类会引起多重继承。以下是class语句的一般形式:

class <name>(superclass,...):
    data = value
    def method(self,...):
        self.member = value

在class语句内,任何赋值语句都会产生类属性,而且还有特殊名称方法重载运算符。

例子

类就像模块和函数:

       就像函数一样,class语句是本地作用域,由内嵌的赋值语句建立的变量名,就存在于这个本地作用域。

       就像模块内的变量名,在class语句内赋值的变量名会变成类对象中的属性。

类的主要的不同之处在于其命名空间也是Python继承的基础。在类或实例对象中找不到的所引用的属性,就会从其他类中获取。

       由上述实例可以看到:属性附加在类上时,变量名是共享的;附加在实例上时,变量名是属于每个实例的数据,而不是共享的行为或数据。

方法

方法位于class语句的主体内,是由def语句建立的函数对象。与简单函数的区别:方法的第一个参数总是接收方法调用的隐性主体,也就是实例对象。

方法调用需通过实例:

instance.method(args...)

这会自动翻译成以下形式的类方法函数调用:

class.method(instance, args...)

在类方法中,按惯例第一个参数通常都称为self。这个参数给方法提供了一个钩子,从而返回调用的主体,也就是实例对象:因为类可以产生许多实例对象,所以需要这个参数来管理每个实例彼此各不相同的数据。self一定要在程序代码中明确地写出:方法一定要通过self来取出或修改由当前方法调用或正在处理的实例的属性。这个变量名存在,会让你明确脚本中使用的是实例属性名称,而不是本地作用域或全局作用域中的变量名。

调用超类构造函数

要保证子类的构造函数也会执行超类构造时的逻辑,一般都必须通过类明确地调用超类的__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)

继承

在Python中,当对对象进行点号运算时,就会发生继承,而且涉及了搜索属性定义树(一个或多个命名空间)。每次使用object.attr形式的表达式时,Python会从头至尾搜索命名空间树,先从对象开始,寻找所能找到的第一个attr。

属性树的构造

总结命名空间树构造以及填入变量名的方式。通常来说:

       实例属性是由对方法内self属性进行赋值运算而生成的。

       类属性是通过class语句内的语句(赋值语句)而生成的。

       超类的连接是通过class语句首行的括号内列出类而生成的。

继承方法的专有化

子类可以完全取代继承的属性,提供超类可以找到的属性,并且通过已覆盖的方法回调超类来扩展超类的方法:

Sub.method只是扩展了Super.method的行为,而不是完全取代了它。

类接口技术

class Super:
    def method(self):
        print('in Super.method')
    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()

运行结果:

抽象超类

当通过Provider实例调用delegate方法时,有两个独立的继承搜索会发生:

1.在最初的x.delegate的调用中,Python会搜索Provider实例和它上层的对象,知道在Super中找到delegate的方法。实例x会像往常一样传递给这个方法的self参数。

2.在Super.delegate方法中,self.action会对self以及它上层的对象启动新的独立继承搜索。因为self指的是Provider实例,在Provider子类中就会找到action方法。

像上述这种类的部分行为默认是由其子类所提供,这样的超类称作为抽象超类。

我们可以在抽象超类中添加assert语句或者引发内置的异常NotImplementedError来触发调用异常。

class Super:
    def method(self):
        print('in Super.method')
    def delegate(self):
        self.action()
    def action(self):
        assert False, 'action must be defined!' # raise NotImplementedError('action must be defined!')

这样,当我们使用如下语句调用这个抽象超类的时候就会触发异常:

x = Super()
x.delegate()

assert False, 'action must be defined!' # raise NotImplementedError('action must be defined!')
AssertionError: action must be defined!

Python2.6和Python3.0的抽象超类

抽象超类需要由子类填充的方法,它们也可以以特殊的类语法来实现。不同版本写法不同:

在Python3.0中,我们在一个class头部使用一个关键字参数,以及特殊的@装饰器语法:

from adc import ABCMeta, abstractmethod
class Super(metaclass = ABCMeta):
    @abstractmethod
    def method(self, ...):
        pass

在Python2.6中,我们使用一个类属性:

class Super:
    __metaclass__ = ABCMeta
    @abstractmethod
    def method(self, ...):
        pass

上述实例可以看出:带有一个抽象方法的类是不能继承的(即,我们不能通过调用它来创建一个实例),除非其所有的抽象方法都已经在子类中定义了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值