【问题标题】:Is there a Python equivalent for Swift's @dynamicMemberLookup?Swift 的 @dynamicMemberLookup 是否有 Python 等价物?
【发布时间】:2019-11-14 19:59:17
【问题描述】:

Swift 中,您可以定义@dynamicMemberLookup (see documentation) 以直接访问嵌套在其他类型中的属性。是否有 Python 等效项?

我想用Python 实现的示例

假设我有一个有成员的班级,例如:

c = OuterClass()
c.inner_class = ClassWithManyMembers()
c.inner_class.member1 = "1"
c.inner_class.member2 = "2"
c.inner_class.member3 = "3"

我希望能够获取/设置这些成员,而不必每次都输入inner_class

print(c.member1)  # prints "1"
c.member1 = 3
print(c.member1)  # prints "3"

Swift (Source) 中的示例:

按成员名称动态查找成员

@dynamicMemberLookup
struct DynamicStruct {
    let dictionary = ["someDynamicMember": 325,
                      "someOtherMember": 787]
    subscript(dynamicMember member: String) -> Int {
        return dictionary[member] ?? 1054
    }
}
let s = DynamicStruct()

// Use dynamic member lookup.
let dynamic = s.someDynamicMember
print(dynamic)
// Prints "325"

通过键路径动态查找成员

struct Point { var x, y: Int }

@dynamicMemberLookup
struct PassthroughWrapper<Value> {
    var value: Value
    subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
        get { return value[keyPath: member] }
    }
}

let point = Point(x: 381, y: 431)
let wrapper = PassthroughWrapper(value: point)
print(wrapper.x)

我在Python 中唯一的想法是将monkey-patch 的所有嵌套属性直接传递给外部类。

【问题讨论】:

  • 您通过成员名称调用 Dynamic 的用例直接在 python 中工作。只是您没有访问 dict 项目的功能。 dyn = s.someDynamicMember,然后是动态['whatever']

标签: python swift monkeypatching keypaths


【解决方案1】:

我建议不要将类相互嵌套,但如果你必须这样做,试试这个:

class MetaOuter(type):
    def __getattr__(cls, attr):
        for member in cls.__dict__.values():
            if hasattr(member, attr):
                return getattr(member, attr)
        raise AttributeError(attr)

    def __setattr__(cls, attr, value):
        for member in cls.__dict__.values():
            if hasattr(member, attr):
                setattr(member, attr, value)
                return
        super().__setattr__(attr, value)


class Outer(metaclass=MetaOuter):
    a = 0

    class Inner:
        x = 1
        y = 2

现在Outer 内嵌套类的任何属性都可以作为Outer 的属性使用(并且可以写入):

>>> Outer.x, Outer.y
(1, 2)
>>> Outer.a # Accessing regular attributes still works as usual
0
>>> Outer.x = True
>>> Outer.Inner.x
True

如果您需要嵌套多个级别,请对任何内部封装类使用相同的元类:

class Outer(metaclass=MetaOuter):
    a = 0

    class Inner(metaclass=MetaOuter):
        x = 1
        y = 2

        class Innerer:
            z = 42
>>> Outer.a, Outer.x, Outer.y, Outer.z
(0, 1, 2, 42)
>>> Outer.z = -1
>>> Outer.z
-1

注意:请注意,如果您尝试访问在多个嵌套类中找到的属性,则无法确定该属性来自哪个类。在这种情况下,一个更可预测的实现是处理某种将被查找的关键路径,但这与 Python 默认提供的基本相同(例如,Outer.Inner.Innerer.z)。

【讨论】:

  • 这是否也适用于直接从我的类中的字典访问值(而不是嵌套类示例)?
  • 我不确定你的意思。您能否提供一个代码示例来说明您希望能够做什么(在 Python 中)?
  • 这不是真正的嵌套类,只是直接访问属性的属性。
  • @chepner 您发布的解决方案是我一直在使用的解决方案。我只是不确定是否有一种通用方法可以使任何嵌套属性可用,而不必每次都保存对内部属性的引用。但是,我的问题/示例集中在class,所以这对我来说很糟糕。你们都是对的,都帮助了我。谢谢!
【解决方案2】:

一般来说,当你想重复访问它时,你可以只保存对内部对象的引用。

c = OuterClass()
c.inner_class = ClassWithManyMembers()

ic = c.inner_class
print(ic.member1)
print(ic.member2)
print(ic.member3)

ic.member1 = "5"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-29
    • 2012-07-17
    • 2012-06-14
    • 2014-01-09
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多