【问题标题】:Use outer class instance as self in inner class?在内部类中使用外部类实例作为自我?
【发布时间】:2018-09-16 00:58:39
【问题描述】:

我正在为GMAIL API 编写一个包装器。在这个包装器中,我试图在“主类”中包含子属性,因此它更接近于以下内容:

以前,我使用的方法如下:

class Foo:
    def __init__(self, ...):
        # add some attributes

    def get_method(self, ...):
        return some_stuff

这让我可以做foo.get_method(...)。为了遵循 GMAIL API,我尝试这样做:

class Foo:
     def __init__(self, ...):
         # add some attributes

     @property
     def method(self):
         class _Method:
             @staticmethod
             def get(self, ...):
                 return some_stuff
         return _Method()

这让我可以做到foo.method.get(...)。上面有一些问题,它每次都重新定义类,我必须在每个方法上方添加@staticmethod作为它的一部分。我确实意识到我可以在外部类级别创建类,并为每个隐藏变量设置一个隐藏变量,然后 .method 返回或创建,但这似乎是太多的解决方法。

tldr:是否可以将传递给内部类的实例作为self作为外部类的实例(我不希望必须传递外部类的属性到每个内部类)。

【问题讨论】:

  • 你的意思是“使用类定义,以便所有函数都被命名空间”?还有什么是外部类?你的问题不清楚。
  • 这怎么不清楚?命名空间 = 所有函数都包含在类中,因此我不会污染模块的全局命名空间 - 如果我确实有 _name,我仍然不喜欢拥有那么多函数。
  • 不清楚,因为我不明白你想做什么/完成什么。我能进一步说的唯一一件事是,如果它更容易理解,你可能会得到更好的答案......
  • 我清楚地概述了我想要什么(根据我的意愿),我尝试过什么,然后是最后的问题?还有什么更清楚的吗?
  • 好吧,更具体地说,将函数放在一个类中只是为了将它们放在一个命名空间中是不寻常的(而且可能是不必要的)——但如果这样做了,就不会有self 类涉及的实例,只是类名本身。因此不清楚你在说什么self。您还没有定义外部类是什么,也没有定义它在这一切中扮演的目的或角色。

标签: python library-design


【解决方案1】:

与其在类之间共享 self 参数,不如将所需的东西传递给实例化类的构造函数。

class Messages:
    def __init__(self, name):
        self.name = name

    def method(self, other_arg):
        return self.name + other_arg

class Test:
    name = "hi"

    def __init__(self):
        self.messages = Messages(name=self.name)

如果您需要将大量信息传递给构造函数并且它开始变得笨拙,您可以执行一些操作,例如将共享代码拆分为第三个类,然后将其作为单个对象在 Test 和 Messages 类之间传递。

在 Python 中,您可以使用元类和魔术方法来做各种聪明的事情,但在 99% 的情况下,只需将事物重构为不同的类和函数,就能让您的代码更具可读性和可维护性。

【讨论】:

  • 您可能会将消息实例化为 Test 中的属性,而不是属性。对此,Propery 太糖了,更重要的是,您可能还想在某处保存更改,例如设置。属性不允许这样做。
  • 虽然这确实提供了一种更好的方法,但这个问题实际上是在询问它是否可能以及如果可能的话如何。我知道我应该以不同的方式来做(我可能会这样做),但这是一个尝试一些有趣的 Python 功能的项目。
  • @Modelmat,您改变主意并专注于表述不当的问题,有点浪费其他人的时间。
  • @Modelmat,仔细检查 Stack Overflow 是否真的适合你。
  • @Modelmat 的问题是一个合理的问题,但还没有真正得到回答。在我看来,它确实值得一个直接的答案。 (顺便说一句,快速的回答是“是的,我认为你可以,虽然没有多少人使用它,我必须查找如何做到这一点。”)
【解决方案2】:

用户应该有一个消息实例,它允许方法获取。代码截图为:

class Messages:
      ...
      def get()
            ...


class Users:
      ...
      messages = Messages(...)

允许

users =  Users()
users.messages.get()

这个 API 的坏处是复数名称,这对类来说是一个不好的迹象。如果从头开始,您宁愿拥有 User 和 Message 类,这更有意义。

如果您仔细查看链接提供的 API 中的 GET/POST 调用,您会注意到 URL 类似于 UserId/settings,这是实现用户类而不是用户的另一个提示。

【讨论】:

  • 我实际上有一个名为 Inbox 的类 - 我没有使用 Users。顺便说一句,您的代码不正确且无效(您需要在 def get() 中有一个 self),并且它没有在它周围的任何地方传递 self。
  • 您指出的是 GMAIL API 的问题。我不会为了遵守所有风格指南而反对它,我只是想为这个问题提供一些粗略的上下文以避免 XY 问题 - 我只想要属性。
  • @Modelmat,请仔细阅读“scetch”这个词。它旨在让您了解需要做什么 - 相应地放置 __init__ 和 self。
  • 我在谷歌上找不到“scetch”这个词的任何含义。你的回答根本没有提供任何有用的东西,正如之前所说,我希望这样做 - 我已经尝试过这样做,但它没有达到我想要的效果。
  • 当然,坚持使用你拥有的代码,它是一个人工制品。
【解决方案3】:

方法中的self引用了外部类的self

也许这就是你想要的factory-method

尽管我将在下面提供的示例代码可能与已经提供的答案相似,并且上面指向另一个答案的链接可能会满足您的愿望,因为它的形式略有不同,但我仍然会就您的问题提供我的看法.代码一目了然。

class User:
    def __init__(self, pk, name):
        self.pk = pk
        self.name = name
        self._messages = None

    def messages(self):
        if self.messages is None:
            self._messages = Messages(self.pk)
        return self._messages


class Messages:
    def __init__(self, usr):
        self.usr = usr

    def get(self):
        return self._grab_data()

    def _grab_data(self):
        # grab the data from DB
        if self.usr == 1:
            print('All messages of usr 1')
        elif self.usr == 2:
            print('All messages of usr 2')
        elif self.usr == 3:
            print('All messages of usr 3')



one = User(1, 'One')
two = User(2, 'Two')
three = User(3, 'Three')

one.messages().get()
two.messages().get()
three.messages().get()

messages 方法的实用性对于标签、历史等是相同的。

编辑:我会再试一次,试图理解你想要达到的目标,即使你说过

我已经尝试了很多方法来定义容器类之外的类 [...]

。我不知道你是否尝试过继承,因为你的内部类me,尽管它在这里并不代表什么,但看起来你仍然想以某种方式利用它的功能。你也说了

方法中的self引用了外部类的self

在我看来,这听起来像是你想要在最后继承。 那么要走的路将是(使用继承的邻近想法):

class me(object):
    def __init__(self):
        self.__other_arg = None # private and hidden variable
    # setter and getter methods
    def set_other_arg(self, new_other_arg):
        self.__other_arg = new_other_arg
    def get_other_arg(self): 
        return self.__other_arg

class Test(me):
    name = 'Class Test'
    @property
    def message(self):
        other_arg = self.get_other_arg()
        if other_arg is not None:
            return '{} {}'.format(self.name, other_arg)
        else:
            return self.name

t = Test()
t.set_other_arg('said Hello')
print(t.message)
# output >>> Class Test said Hello

我认为这可能是一种更可取的方法,而不是你的内部阶级方法,我认为,你会决定的。只是一个侧面说明,在 python 中查找 getter 和 setter,如果你想坚持给定的继承思想,它可能会对你有所帮助。

【讨论】:

  • 这不符合原始问题中的任何要求,并且没有任何相关性。链接的问题也不相关,并且与其他两个答案具有相同的问题。
  • @Modelmat,您不再收到答案,而且您得到了一些反对意见。为了弥补这一点,我又试了一次给你一个好的答案。看看这是否能以某种方式帮助你。祝你好运!
  • 虽然我很欣赏这种尝试,但继承也不是我想要的。我希望能够使用foo.method.get。这并不能解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多