TypeError: __init__() takes exactly 1 argument (2 given) 引发的原理分析

在代码调试的过程中,报错如下:
在这里插入图片描述
TypeError: init() takes exactly 1 argument (2 given) 引发的原理分析

以下的分析问题的过程
查看代码

from abc import abstractmethod,ABCMeta

class Rootfunction(object):
    __metaclass = ABCMeta
    
    def __init__(self,driver=None):
        self.driver = driver
        
    @abstractmethod
    def __init__(self):
        pass 
    
    def get_method(self,name):
        return self.driver.get(name)   
    
    def get_all_func(self):
        return self.driver.get("all_function")

可以看到,写了一个抽象类,抽象类就是类的集成,换言之是一组具有相似性的类,包括数据属性和函数属性,而接口只强调函数属性的相似性。
普通类可以实例化和继承,而抽象类不能实例化,只能子类继承,然后子类去实现继承的方法,除非子类也是抽象类。
接口是对动作的抽象
抽象类是对本质的抽象
举个简单的例子

"""
抽象类
"""
import abc  # 利用abc模块实现抽象类


# 一切皆文件
class All_file(metaclass=abc.ABCMeta):
    all_type = 'file'

    @abc.abstractmethod  # 定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        pass

    @abc.abstractmethod  # 定义抽象方法,无需实现功能
    def write(self):
        '''子类必须定义写功能'''
        pass


class Txt(All_file):  # 子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的写入方法')


class Sata(All_file):  # 子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的写入方法')


class Process(All_file):  # 子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的写入方法')


wenbenwenjian = Txt()
yingpanwenjian = Sata()
jinchengwenjian = Process()

# 这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

# 这样大家都是被归一化了,也就是一切皆文件的思想
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

回到解决问题上面,如下图,第一个@abstractmethod是报错的代码,第二个@abstractmethod和第三个@abstractmethod都是经常修改都是可以正常运行的代码

from abc import abstractmethod,ABCMeta

class Rootfunction(object):
    __metaclass = ABCMeta

    def __init__(self,driver=None):
        self.driver = driver

    @abstractmethod               # 1
    def __init__(self):
        pass
    # @abstractmethod             # 2
    # def init(self):
    #     pass
    # @abstractmethod             # 3
    # def __init__(self,drive=None):
    #     pass
    def get_method(self,name):
        return self.driver.get(name)

    def get_all_func(self):
        return self.driver.get("all_function")

那么问题来了,为什么第二个@abstractmethod和第三个@abstractmethod都可以正常运行呢?
首先看一下子类怎么写的
在这里插入图片描述
由图可知,第三个@abstractmethod是改写了父类的初始化方法__init__,虽然可以正常运行,但是会影响后续的性能。见下图父类
在这里插入图片描述
为什么第二个是合适的呢,让我们来重新梳理一下整个代码逻辑
在子类TestClass中,初始化方法里用了super().init,这个是用来做什么的呢?

class Root(object):
    def __init__(self):
        self.x = '属性'

    def fun(self):
        print(self.x)
        print('方法')

class A(Root):
    def __init__(self):
        super(A, self).__init__()
        print('实例化执行')

test = A()  # 实例化类
test.fun()  # 调用方法
test.x      # 调用属性

执行结果:

实例化执行
属性
方法

如果不加super().init()会执行出什么

class Root(object):
    def __init__(self):
        self.x = '属性'
    def fun(self):
        print('方法')

class A(Root):
    def __init__(self):
        print('实例化执行')

test = Root()   # 实例化类
test.fun()      # 调用方法
test.x          # 调用属性

执行如下:

方法

可以看到此时父类的方法继承成功,可以使用,但是父类的属性却未继承,并不能用
再试一种方法

class Root(object):
    def __init__(self):
        self.x = '属性'

    def fun(self):
        print('self.x')
        print('方法')

class A(Root):
    def __init__(self):
        print('实例化时执行')

test = A()   # 实例化方法
test.fun()   # 调用方法
test.x       # 调用属性

执行结果如下:

实例化时执行
self.x
方法
Traceback (most recent call last):
  File "E:/code/September/025.py", line 47, in <module>
    test.x       # 调用属性
AttributeError: 'A' object has no attribute 'x'

Process finished with exit code 1

这样也可以看出,还是不能调用父类的属性

经过三次测试,可以看出,super().__init__是用来执行父类的构造函数,使得我们能够调用父类的属性。
(还有一种Root.init(self),在继承时会跳过重复继承,节省了资源,后面遇到再进行专门分析)
回到正题,看下图
在这里插入图片描述
在__init__方法里,子类调用父类的属性
在init方法里,子类对抽象类的父类进行继承重写
用第一种@abstractmethod和第三种@abstractmethod会将父类的__init__方法覆盖掉,第三种虽然可以运行,但在业务逻辑上是有问题的。

from abc import abstractmethod,ABCMeta

class Rootfunction(object):
    __metaclass = ABCMeta

    def __init__(self,driver=None):
        self.driver = driver

    @abstractmethod               # 1
    def __init__(self):
        pass
    # @abstractmethod             # 2
    # def init(self):
    #     pass
    # @abstractmethod             # 3
    # def __init__(self,drive=None):
    #     pass
    def get_method(self,name):
        return self.driver.get(name)

    def get_all_func(self):
        return self.driver.get("all_function")

用第二种```python
from abc import abstractmethod,ABCMeta

class Rootfunction(object):
__metaclass = ABCMeta

def __init__(self,driver=None):
    self.driver = driver

@abstractmethod               # 1
def __init__(self):
    pass
# @abstractmethod             # 2
# def init(self):
#     pass
# @abstractmethod             # 3
# def __init__(self,drive=None):
#     pass
def get_method(self,name):
    return self.driver.get(name)

def get_all_func(self):
    return self.driver.get("all_function")
即用第二种问题解决。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今晚务必早点睡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值