【问题标题】:Python multiple classes inheritance error. How can I initialize them correctly?Python 多类继承错误。如何正确初始化它们?
【发布时间】:2023-03-25 01:14:01
【问题描述】:

我正在尝试为我编写的 HTTP RESTful API 构建一个 python3 模块。

我的想法是创建一个base 类,它应该有一个request.Session() 属性,这样我就可以为其分配一个授权令牌标头,而不必再担心它以及一个记录器功能等等。 问题是一个名为User 的类继承自两个类:PublicUserbase,我无法正确初始化它们。

这是我第一次使用继承类,所以显然我遗漏了一些东西。

这是我的文件夹结构:

examplemodule/
  |--> __init__.py
  |--> classes/
        |-->  base.py
        |-->  user.py

base.py

from requests import Session
from requests.sessions import session


class Logger:
    def __init__(self):
        pass

    def log(self, message):
        print(message)


class Base:
    def __init__(self, token=None):
        if not hasattr(self, 'logger'):
            self.logger = Logger()
        if not hasattr(self, 'session'):
            self.session = Session()
            self.session.headers.update(
                {'authorization': 'Token {}'.format(token)}
            )
            # Try to login to see if token is valid, if not raise exception
            # If token is valid then the retrieved user json is saved
            self._user = {
                'id': 1,
                'username': 'test1',
                'email': 'test@test.com'
            }

user.py

from .base import Base

PUBBLIC_USER_ATTRS = ['id', 'username']
PRIVATE_USER_ATTRS = ['email']


class PublicUser:
    def __init__(self, user):
        for k in PUBBLIC_USER_ATTRS:
            setattr(self, k, user[k])


class User(Base, PublicUser):
    def __init__(self, token=None):
        super(Base, self).__init__(token=token)
        super(PublicUser, self).__init__(self._user)
        for k in PRIVATE_USER_ATTRS:
            setattr(self, k, self._user[k])

__init__.py

from .classes.user import User

然后测试我运行的模块:

import examplemodule
examplemodule.User(token='')

但不幸的是,我在super(Base, self).__init__(token=token) 收到了TypeError

TypeError: super() 没有关键字参数

解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: python python-3.x inheritance multiple-inheritance


    【解决方案1】:

    您可能希望像这样调用超类的构造函数:

    Base.__init__(self, token=token)
    PublicUser.__init__(self, self._user)
    

    【讨论】:

    • 这种方法和@chepner 的方法有什么区别?
    • 这只是我的意见,但我认为这更明确和可读。这是我看到的唯一区别。您可以使用更自我记录的普通参数,而不是 **kwargs
    【解决方案2】:

    super 用于合作 继承,其中所有涉及的类都使用super,以确保调用所有必要的方法。这意味着super 应该被基类使用,即使它们继承自object

    class Base:
        def __init__(self, *, token=None, **kwargs):
            super().__init__(**kwargs)
            if not hasattr(self, 'logger'):
                self.logger = Logger()
            if not hasattr(self, 'session'):
                self.session = Session()
                self.session.headers.update(
                    {'authorization': 'Token {}'.format(token)}
                )
                # Try to login to see if token is valid, if not raise exception
                # If token is valid then the retrieved user json is saved
                self._user = {
                    'id': 1,
                    'username': 'test1',
                    'email': 'test@test.com'
                }
    
    class PublicUser:
        def __init__(self, *, id, username, **kwargs):
            super().__init__(**kwargs)
            self.id = id
            self.username = username
            
    class User(Base, PublicUser):
        def __init__(self, *, email, **kwargs):
            super().__init__(**kwargs)
            self.email = email
    
    
    u = User(token='...', id='...', username='...', email='...')
    

    User.__init__ 只需调用一次super().__init__,知道它的基类也使用super().__init__ 总是调用下一个__init__,直到到达 MRO 的末尾。你从User.__init__开始,它调用Base.__init__,它调用PublicUser.__init__不是object.__init__),它最终调用object.__init__

    在每个步骤中,剩余的关键字参数被拆分为处理的“已知”参数和向上传递的“未知”参数。最终,在调用object.__init__ 之前,所有关键字对象都应该被提取和处理。

    请参阅https://rhettinger.wordpress.com/2011/05/26/super-considered-super/,以更全面地了解其在实践中的工作原理(特别是为什么关键字参数优于位置参数)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      相关资源
      最近更新 更多