【问题标题】:python property referring to property/attribute of member attribute?python属性指的是成员属性的属性/属性?
【发布时间】:2018-07-18 07:34:35
【问题描述】:

我想知道我是否有:

class A(object):
    def __init__(self):
        self.attribute = 1
        self._member = 2
    def _get_member(self):
        return self._member
    def _set_member(self, member):
        self._member = member
    member = property(_get_member, _set_member)

class B(object):
    def __init__(self):
        self._member = A()
    def _get_a_member(self):
        return self._member.member
    def _set_a_member(self, member):
        self._member.member = member
    member = property(_get_a_member, _set_a_member)

我是否可以避免为 A.member 编写 get/setter,而只引用 A 对象的属性或属性?

get/setter 在哪里执行逻辑,当然需要它,但如果我只是不想公开成员属性的成员/属性,那么编写 get/setter 似乎是开销。

我认为即使我可以内联编写 get/setters 也会有所帮助?

【问题讨论】:

  • OP 中缺少的一些上下文:我试图隐藏 A 类的具体实现,因为它是第 3 方实现,我希望能够在后期,与其他一些第 3 方实施。具体来说,B 在 NIPAP IPAM 系统中抽象了一个 IP 前缀(A 类),我希望能够维护 B 类的接口,并且仍然能够更改 B 的实现以使用其他具有替代方案的 IPAM 系统IP 前缀的实现。

标签: python-3.x class properties


【解决方案1】:

我觉得这个问题有点不清楚,但我尝试解释一些上下文。

get/setter 在哪里执行逻辑,当然需要它,但如果我只是不想公开成员属性的成员/属性

如果getter/setter中没有逻辑,则不需要将属性定义为property,但是可以直接使用该属性(在任何上下文中)。

所以

class A(object):
    def __init__(self):
        self.attribute = 1
        self.member = 2

class B(object):
    def __init__(self):
        self.member = A()

B().member.member  # returns 2
B().member.member = 10

在某些语言中,使用 getter/setter 方法抽象实例属性被认为是一种很好的做法,但在 Python 中不一定是这种情况。 当您需要对属性进行更多控制时,Python 属性很有用,例如:

  • 当有逻辑(验证等)时
  • 定义一个只读属性(所以只提供一个没有设置器的getter)

更新(评论后)

属性不一定是“隐藏”某些内部实现的工具。由于 Python 语言的动态特性,Python 中的隐藏与 Java 中的隐藏有点不同。总是可以动态内省甚至更改对象,您可以在运行时向对象添加新属性(甚至方法):

b = B()
b.foo = 4  # define a new attribute on runtime
b.foo  # returns 4

因此 Python 开发人员更多地依赖 conventions 来暗示他们的抽象意图。

关于多态成员,我认为 Python 类只共享一个接口是最自然的,这就是 Duck typing 的意思。因此,只要您的 A 的下一个实现支持相同的接口(为调用者提供相同的方法),更改其实现应该没有任何问题。

【讨论】:

  • 我会在一定程度上同意,但在我的情况下,我想隐藏内部实现,以便我在稍后阶段可以将 A 对象替换为执行相同操作的其他对象任务(隐藏内部驱动程序),而不必使用 B 类重构模块 - 也许那不是非常 Pythonic,而且我大部分时间都在做 Java,所以我可能遗漏了一些东西.. 但感谢您的回复,请告诉我如果我的“隐藏”倾向本质上是错误的和不符合 Python 的?
  • 对,但那是我的问题 - A 类是第 3 方实现,如果它被替换,它将与其他一些第 3 方实现一起使用,我无法控制 - 所以替换 A 可能没有 self.member,而是 self.some_other_member 甚至是 setter/getter。我意识到我完全忽略了在问题中包含大部分内容,所以我会接受你的回答。如果我仍在尝试真正的道路,我真的很感激评论。
  • 情况似乎有所不同。然后似乎需要完全抽象A 并将其作为实现细节保留在B 中。那么 IMO 一个不错的选择是 B 改为 wrap AB 可以将A 实例存储为self.__member__ 暗示它是私有成员,不应直接访问),B 将具有来自A 的每个所需方法的方法(可能与一个更通用的名称),它在内部调用来自A 的方法。现在B 的用户将不知道A 及其方法(除非他们忽略约定)。以后很容易用不同的类更改A
【解决方案2】:

所以这就是我想出的 - 使用一种方法来生成属性,假设 obj 具有 _member 的属性:

def generate_cls_a_property(name):
    """Small helper method for generating a 'dumb' property for the A object"""
    def getter(obj):
        return getattr(obj._member, name)

    def setter(obj, new_value):
        setattr(obj._member, name, new_value)

    return property(getter, setter)

这允许我添加如下属性:

class B(object):
    def __init__(self):
        self._member = A()
    member = generate_cls_a_property('member')  # generates a dumb/pass-through property

我会接受我自己的,除非有人在一周内超过它.. :)

【讨论】:

    猜你喜欢
    • 2010-10-08
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多