Python替代dict风格的二传手? [英] Pythonic alternative to dict-style setter?
问题描述
人们倾向于认为getter和setter是非Python语言的,而是倾向于使用 @property
.我目前正在尝试扩展使用 @property
来支持字典的类的功能:
People tend to consider getters and setters un-Pythonic, prefering to use @property
instead. I'm currently trying to extend the functionality of a class that uses @property
to support a dict:
class OldMyClass(object):
@property
def foo(self):
return self._foo
@foo.setter
def foo(self, value):
self.side_effect(value)
self._foo = value
class NewMyClass(object):
@property
def foo(self, key): # Invalid Python
return self._foo[key]
@foo.setter
def foo(self, key, value): # Invalid Python
self.side_effect(key, value)
self._foo[key] = value
当然,我可以创建一些帮助程序类来解决此问题,但是似乎只编写带有键和值的setter/getter函数会容易得多.但是,有没有一种更Python化的方法来进行这种重构?
Of course, I could create some helper classes to deal with this, but it seems like just writing setter/getter functions that take a key and value would be much simpler. But is there a more Pythonic way to do this refactor?
推荐答案
您所描述的不是属性的情况.这些属性用于允许 obj
(或更确切地说,其类)自定义 obj.prop = value
的行为.如果您要自定义 obj.prop [key] =值
,则需要处理的不是 obj
,而是 obj.prop
,这意味着您需要将 obj.prop
设为自定义类.您想要在这里创建一个带有 __ setitem __
的自定义类.
What you describe is not a case for properties. Properties are for allowing obj
(or rather, its class) to customize the behavior of obj.prop = value
. If you want to customize obj.prop[key] = value
, then you need to handle that not in obj
but in obj.prop
, which means you need to make obj.prop
be a custom class. What you want here is to create a custom class with a __setitem__
.
class Foo(object):
def __init__(self):
self._vals = {}
def __setitem__(self, key, val):
do_side_effect(key, val)
self._vals[key] = val
然后在MyClass的 __ init __
中,执行 self.foo = Foo()
.
Then in your MyClass's __init__
, do self.foo = Foo()
.
如果您想让类似dict的对象知道其父对象是什么(例如,由于副作用应发生在父对象上,则将父对象作为参数传递给Foo:
If you want this dict-like object to know what its parent object is (e.g., because the side effect should take place on the parent, then pass the parent as an argument to Foo:
class Foo(object):
def __init__(self, parent):
self.parent = parent
self._vals = {}
def __setitem__(self, key, val):
parent.do_side_effect(key, val)
self._vals[key] = val
然后在 MyClass .__ init __
中执行 self.foo = Foo(self)
.
关于吸气剂/吸气剂,您正在做的不是典型的吸气剂/吸气剂.不鼓励使用的是诸如 getSomeProp()
和 setSomeProp(value)
之类的东西,其中为您获取/设置的每个属性都有一个单独的方法.在您的示例中,您描述的是不同的东西,这是用于设置键值对的通用get/set机制(可能对对象的行为具有某种意义).拥有方法 setPair(key,value)
并不比拥有名为 doSomething(arg1,arg2)
的方法更糟糕.这里有一个额外的参数,因此您的任务不适合 obj.key = value
的简单模式.如果希望 obj.prop [key] =值
中的键/值了解" obj
,则还需要一个间接层.在像 obj.prop [key] = value
这样的赋值中,键和值是从 obj
中删除的一步,并且只能直接与 prop
进行交互
With regard to getters/setters, what you're doing is not a typical getter/setter. The kind of thing that is discouraged is things like getSomeProp()
and setSomeProp(value)
, where there is a separate method for each property that you get/set. In your example, you're describing something different, which is a generalized get/set mechanism for setting key-value pairs (which presumably have some meaning for the object's behavior). Having a method setPair(key, value)
is not any worse than having a method called doSomething(arg1, arg2)
. Here you have an extra parameter, so your task doesn't fit into the simple pattern of obj.key = value
. You also have an extra layer of indirection if you want the key/value inobj.prop[key] = value
to "know about" obj
; in an assignment like obj.prop[key] = value
, the key and value are one step removed from obj
and interact directly only with prop
.
您也可以使用John Smith Optional建议的简单方法来完成此操作.您是要这样做还是要像我描述的那样使用自定义对象,取决于您希望API的设置方式.将代码围绕自定义数据保存"类(如我在此处概述的类)构建可能会带来可读性的好处,但这确实使实现变得更加复杂.
You could also do it with a simple method as John Smith Optional suggests. Whether you want to do it that way or with a custom object like I described depends on how you want the API set up. There can be readability benefits to having the code built around custom "data-holding" classes like the one I outlined here, but it does make the implementation a bit more complex.
这篇关于Python替代dict风格的二传手?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!