【问题标题】:Python: method with variable name for setting value of an objectPython:用于设置对象值的变量名方法
【发布时间】:2014-04-25 21:13:28
【问题描述】:

让我们有一个简单的类,其中包含设置它们的值和方法:

class Object:
  def __init__(self, id):
      self.__id = id
      self.__value1 = None
      self.__value2 = None
      ... etc

  def set_value1(self, value1):
      self.__value1 = value1
  def set_value2(self, value2):
      self.__value2 = value2
      ... etc

我能否以某种方式将这些 .set_valueX(valueX) -函数合并为一个,这是如何发生的?在没有导入库的情况下是否可以轻松完成?

【问题讨论】:

  • 那么有可能还是我必须为每个 init 分别编写相同的重复 .set_value() 函数?

标签: python class variables object methods


【解决方案1】:

可以使用 setatter 来完成:

class obj(object):

    def __setter(self,**kwargs):
        key,value = kwargs.items()[0]
        setattr(self,"__"+key,value)

    def __init__(self,id):
        self.id = id
        self.__value1 = None
        self.__value2 = None
        #You should assign setter as the set funciton like this:
        self.set_value1 = self.__setter
        self.set_value2= self.__setter
        #and so on...

init 方法可以更短,使用相同的技术。

【讨论】:

    【解决方案2】:

    如果你愿意妥协并使用一个处理所有 setter 逻辑的函数,你可以这样做

    class Test:
        def __init__(self):
            self._value1 = 1
            self._value2 = 2
            self._value3 = 3
    
        def set_value(self, attr, value):
            setattr(x, attr, value)
    

    并通过

    访问每个方法设置器
    test_obj = Test()
    test_obj.set_value("_value1", 10)
    

    但是,我不建议采用任何一种方法。相反,您可能希望通过 @property 装饰器使用 getter 和 setter。

    这是一种更“Pythonic”的方法,更多信息可以在

    中找到

    https://docs.python.org/2/library/functions.html#property

    【讨论】:

      【解决方案3】:

      我会先说 getter 和 setter 不是很pythonic,在这种情况下似乎没有必要。如果您需要自定义获取/设置行为,请考虑使用属性(Python @property versus getters and setters),否则没有理由不以典型方式获取和设置(obj.foo = 'bar'x = obj.foo)。

      但我想如果你真的想……一点点__getattr__ 魔法就可以做到:

      class A(object):
          def __init__(self, id):
              self.__id = id
              self.__value1 = None
              self.__value2 = None
      
          def _setter(self, name):
              def set(value):
                  setattr(self, name, value)
              return set
      
          def __getattr__(self, name):
              if name.startswith('set_'):
                  varname = name.split('_', 1)[-1]
                  return self._setter('__' + varname)
              return super(A, self).__getattr__(name)
      

      允许...

      In [1]: a = A('123')
      
      In [2]: a.set_value1(5)
      
      In [3]: a.__value1
      Out[3]: 5
      
      In [4]: a.set_value2(7)
      
      In [5]: a.__value2
      Out[5]: 7
      

      【讨论】:

        【解决方案4】:

        这很简单,但知道你为什么要这样做会很有帮助。最 Pythonic 的方法可能是拥有一个创建所有访问器函数的元类。如果您尝试正确执行此操作,我会查找 python property 范例。但是,如果您的所有访问器功能都相同,为什么您需要为它们提供单独的功能呢?您可以通过以下方式轻松设置值:

        x = Object()
        x.value = value
        

        ...只要你省去完全不必要的双下划线,至少。如果您确实需要更改对每个属性的每次调用,您可以覆盖 __setattr__ (Python Data Model Reference)。附带说明一下,在我合作过的每个小组中,都非常不鼓励使用 __variable 方法。它不会阻止任何人实际访问该值(您可以通过 instance._Object__value1 进行操作),但它会使子类化变得可怕。

        如果您只想对每个属性获取或设置进行相同的预处理,您总是可以执行以下操作:

        class Object:
           _ATTR_NAMES = ('value1', 'value2', ...)
           def __init__(self):
              for name in self._ATTR_NAMES:
                  setattr(self, "_" + name, None)
        
           def set_attr(self, name, value):
              if name in self._ATTR_NAMES:
                 setattr(self, name[1:], value)
              else:
                 raise AttributeError("No attribute named %s found"%name)
        

        Python 的 setattr 是一个在属性上设置具有给定名称的属性的函数。在这种情况下,您可以简单地拥有一个属性列表,在此基础上设置它们,然后使用相应的“getattr”函数检索它们。不过,我再次警惕您这样做的原因。通常显式优于隐式。很少很难只做一个额外的 get/set 函数来使引用更加清晰。

        如果你真的需要,你也可以使用与我刚刚展示的属性非常相似的技术生成 get/set 函数(即,动态创建包装 set_attr 的函数),但同样,它通常会生成代码更难维护和阅读。除非您确实有强烈而明确的需要,否则我会避免使用其中的许多技术。如果你真的必须这样做,这样的事情会起作用:

        class Object:
           _ATTR_NAMES = ('value1', 'value2', ...)
           def __init__(self):
              for name in self._ATTR_NAMES:
                  setattr(self, "_" + name, None)
        
           def _set_attr(self, name, value):
              if name in self._ATTR_NAMES:
                 setattr(self, name[1:], value)
              else:
                 raise AttributeError("No attribute named %s found"%name)
        
        # This binds named set functions to the class
        for name in Object._ATTR_NAMES:
           def tempSetter(self, value):
               self._set_attr(name, value)
           setattr('set_'+name, tempSetter)
        del name
        del tempSetter
        

        这是一种很老套的做法。在元类中进行这种处理更为优雅。但是,由于需要大量背景知识才能理解,因此我将跳过该内容。如果您需要在每个 set 函数之前进行预处理,通常更倾向于按照以下方式进行操作:

        def _preprocessing(self, value):
           # Do something here
           return value
        
        def set_value1(self, value):
           value = self._preprocessing(value)
           self._value1 = value
        
        def set_value2(self, value):
           value = self._preprocessing(value)
           self._value2 = value
        

        最后,如果您担心的只是生成样板 get/set 函数的时间,那么只需编写一个脚本,将您的 Python 类的骨架写为文本文件。我有这些类型的脚本,它们基于原始模块概述了我的单元测试用例。或者在您的文本编辑器中有一个脚本宏。读代码的次数比写代码的次数多,所以不要为了省去几次按键而编写复杂的代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多