Pythonic alternative to dict-style setter?

♀尐吖头ヾ 提交于 2021-01-28 05:06:15

问题


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

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?


回答1:


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

Then in your MyClass's __init__, do self.foo = 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

And then in MyClass.__init__ you do self.foo = Foo(self).

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.

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.



来源:https://stackoverflow.com/questions/22900940/pythonic-alternative-to-dict-style-setter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!