【问题标题】:Can I use another class's property without extending that class?我可以在不扩展该类的情况下使用另一个类的属性吗?
【发布时间】:2023-04-07 16:18:01
【问题描述】:

布雷夫:

我有两个类,其中包含一些相同的属性块对。 这些类共享一个共同的祖先,但也有兄弟姐妹不 需要这些属性。

我不想复制属性代码块。

如果我使用的是 Getter:

使用 Getter,我的方法是在另一个类中调用权威方法:

# in ConcreteFooz.baz_per_bar:
def baz_per_bar(self):
    return ConcreteFoo.baz_per_bar(self)

但我没有使用吸气剂,

@properties 似乎更适合我的需求。 当我尝试时:

# in ConcreteFooz.baz_per_bar:
def baz_per_bar(self):
    return ConcreteFoo.baz_per_bar(self)

我回来了:

*** TypeError: 'property' object is not callable

所以;

我可以在不扩展该类的情况下使用另一个类的属性吗?


示例代码

所以我们通常指的东西:

import itertools

class MyBaseClass(object):
    pass

class ConcreteFoo(MyBaseClass):
    @property
    def baz_per_bar(self):
        """Returns as dict of {baz: list bar}"""
        # do baz lookup
        # do bar lookup
        # associcate and return
        return my_baz_per_bar

    @property
    def baz_chain(self):
        """Flattens baz_per_bar into baz's"""
        return itertools.chain(*self._baz_chain.values())

class ConcreteFooz(MyBaseClass):
    @property
    def baz_per_bar(self):
        """Returns as dict of {baz: list bar}"""
        # do baz lookup
        # do bar lookup
        # associcate and return
        return my_baz_per_bar

    @property
    def baz_chain(self):
        """Flattens baz_per_bar into baz's"""
        return itertools.chain(*self._baz_chain.values())

class ConcreteJaz(MyBaseClass):
    pass
    # Does not need property lookup

【问题讨论】:

  • 我不清楚为什么ConcreteJaz 不只是使用来自MyBaseClass 的正常继承
  • @ChadS。我问这个问题是因为我很惊讶在 python 中发现了一些我做不到的东西。例如,在多个上下文中使用属性。我想知道这是否真的是一个限制。显然还有其他方法可以给这只猫剥皮,这是一个通过继承解决的非常简单的问题。
  • 但我什至不明白你在这里想要完成什么。您不能只是将 @ 语法添加到方法上并让它知道您想要它做什么。那不是how decorators work..
  • @ChadS。在小的 sn-ps 中,我使用 @ 来指代 sn-p 的父级,这可能是一个糟糕的选择,我已将它们更新为 cmets。

标签: python class properties delegates getter


【解决方案1】:

是的,您可以在不扩展该类的情况下使用另一个类的属性。考虑这个程序:

import itertools

class MyBaseClass(object):
    pass

class ConcreteFoo(MyBaseClass):
    def __init__(self):
        self.my_baz_per_bar = { 'A' : ['apple', 'aardvark'] }

    @property
    def baz_per_bar(self):
        """Returns as dict of {baz: list bar}"""
        # do baz lookup
        # do bar lookup
        # associcate and return
        return self.my_baz_per_bar

    @property
    def baz_chain(self):
        """Flattens baz_per_bar into baz's"""
        return itertools.chain(*self._baz_chain.values())

class ConcreteFooz(MyBaseClass):
    def __init__(self):
        self.my_baz_per_bar = { 'Z' : ['zero', 'zebra'] }

    baz_per_bar = ConcreteFoo.baz_per_bar
    baz_chain = ConcreteFoo.baz_chain

class ConcreteJaz(MyBaseClass):
    pass
    # Does not need property lookup

print ConcreteFoo().baz_per_bar
print ConcreteFooz().baz_per_bar

或者,考虑这个片段:

    @property
    def baz_per_bar(self):
        return ConcreteFoo.baz_per_bar.fget(self)

请注意,我确实修改了您的示例中的 ConcreteFoo,但仅修复了其中的 NameError

【讨论】:

    【解决方案2】:

    我不太确定。 mixin 能满足你的需要吗?

    import itertools
    
    class MyBaseClass(object):
        pass
    
    class BazMixin():
        @property
        def baz_per_bar(self):
            """Returns as dict of {baz: list bar}"""
            # do baz lookup
            # do bar lookup
            # associcate and return
            return my_baz_per_bar
    
        @property
        def baz_chain(self):
            """Flattens baz_per_bar into baz's"""
            return itertools.chain(*self._baz_chain.values())
    
    
    class ConcreteFoo(MyBaseClass, BazMixin):
        pass
    
    class ConcreteFooz(MyBaseClass, BazMixin):
        pass
    
    class ConcreteJaz(MyBaseClass):
        pass
        # Does not need property lookup
    

    【讨论】:

    • 我不想接受替代解决方案,因为我不要求替代解决方案。如果我对所提出的确切问题不感兴趣,我会使用已知的工作模式(如 Mixins)来解决这个问题。 see this comment
    • @ThorSummoner 如果您必须引用您所做的评论,那么您可能没有特别准确地写出问题,也没有费心去修复它。没有理由对您的不清晰感到生气。
    猜你喜欢
    • 2016-03-11
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多