是否有 Python 等同于 Swift 的 @dynamicMemberLookup?
Is there a Python equivalent for Swift's @dynamicMemberLookup?
在 Swift
中,您可以定义 @dynamicMemberLookup
(see documentation) 以直接访问嵌套在另一种类型中的属性。是否有 Python
等价物?
我想用 Python
实现的示例
假设我有一个 class 成员,例如:
c = OuterClass()
c.inner_class = ClassWithManyMembers()
c.inner_class.member1 = "1"
c.inner_class.member2 = "2"
c.inner_class.member3 = "3"
我希望能够 get/set 这些成员而不必每次都输入 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
所有嵌套属性直接到外部 class。
我建议不要将 classes 相互嵌套,但如果你必须这样做,试试这个:
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
内的嵌套 class 的任何属性都可用作(并且可以写入)作为 Outer
的属性:
>>> Outer.x, Outer.y
(1, 2)
>>> Outer.a # Accessing regular attributes still works as usual
0
>>> Outer.x = True
>>> Outer.Inner.x
True
如果您需要嵌套多于一层,请对任何内部封装 classes:
使用相同的元 class
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
注意:请注意,如果您尝试访问在多个嵌套 class 中找到的属性,您无法确定该属性来自哪个 class .在这种情况下,更可预测的实现是处理某种将被查找的关键路径,但这与 Python 默认提供的基本相同(例如 Outer.Inner.Innerer.z
)。
一般情况下,当你想重复访问它时,你可以只保存对内部对象的引用。
c = OuterClass()
c.inner_class = ClassWithManyMembers()
ic = c.inner_class
print(ic.member1)
print(ic.member2)
print(ic.member3)
ic.member1 = "5"
在 Swift
中,您可以定义 @dynamicMemberLookup
(see documentation) 以直接访问嵌套在另一种类型中的属性。是否有 Python
等价物?
我想用 Python
实现的示例
假设我有一个 class 成员,例如:
c = OuterClass()
c.inner_class = ClassWithManyMembers()
c.inner_class.member1 = "1"
c.inner_class.member2 = "2"
c.inner_class.member3 = "3"
我希望能够 get/set 这些成员而不必每次都输入 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
所有嵌套属性直接到外部 class。
我建议不要将 classes 相互嵌套,但如果你必须这样做,试试这个:
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
内的嵌套 class 的任何属性都可用作(并且可以写入)作为 Outer
的属性:
>>> Outer.x, Outer.y
(1, 2)
>>> Outer.a # Accessing regular attributes still works as usual
0
>>> Outer.x = True
>>> Outer.Inner.x
True
如果您需要嵌套多于一层,请对任何内部封装 classes:
使用相同的元 classclass 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
注意:请注意,如果您尝试访问在多个嵌套 class 中找到的属性,您无法确定该属性来自哪个 class .在这种情况下,更可预测的实现是处理某种将被查找的关键路径,但这与 Python 默认提供的基本相同(例如 Outer.Inner.Innerer.z
)。
一般情况下,当你想重复访问它时,你可以只保存对内部对象的引用。
c = OuterClass()
c.inner_class = ClassWithManyMembers()
ic = c.inner_class
print(ic.member1)
print(ic.member2)
print(ic.member3)
ic.member1 = "5"