正确/ Pythonic方式处理具有作为参数给出的大量属性的对象

时间:2015-06-24 09:25:26

标签: python class object attributes kwargs

我的情况是一个对象有15个以上的参数,其中一些是强制/可选/有默认值/没有默认值。我们假设课程为Foo,并且参数为Bar1Bar2,...,BarN

我可以像以下那样对课程进行编程:

  1. 传统的,乏味的方式。易于定义默认值和详细信息。但是,代码很长并且有很多重复。

    class Foo(object):
        def __init__(self, bar1, bar2,...barN='somedefault' ):
            self.bar1 = bar1
            self.bar2 = bar2
            ...
            self.barN = barN
    
  2. 滥用(?)kwargs。不支持默认值。

    class Foo(object):
    
        fields = [ 'bar1', 'bar2', ...n 'barN']
    
        def __init__(self, **kwargs ):
            for key in kwargs:
                if key in self.fields:
                    setattr(self, key, kwargs[key])
                else:
                    raise Exception('invalid attribute: {0}'.format(key))
    
  3. 对于数字2,我可以将fields类属性更改为地图{ 'attribute_name': 'default_value' },然后如果该密钥不在default_value中,则分配kwargs

    我工作的背景是我创建的对象与服务器,防火墙规则,存储磁盘等对应,具有很多属性。在很多情况下,我从API获取属性,所以我可以做2号(即使没有验证)。但是,有时用户会创建防火墙规则,将其附加到服务器并将其发送到API(带有JSON正文的POST)。

    是否有一些标准/ pythonic方式来处理具有大量属性的对象? #2中的方法看起来是否合适,或者我应该采用冗长的#1方式?

    编辑:一个具体示例是具有以下参数的防火墙规则对象:

        action
        destination_address_end
        destination_address_start
        destination_port_end
        destination_port_start
        direction
        family
        icmp_type
        position
        protocol
        source_address_end
        source_address_start
        source_port_end
        source_port_start
    

    现在我倾向于这样的事情:

    class FirewallRule(object):
    
        attributes = {
            'action': 'default_value',
            'destination_address_end': 'default_value',
            'destination_address_start': 'default_value',        
            'destination_port_end': 'default_value',
            'destination_port_start': 'default_value',
            'direction': 'default_value',
            'family': 'default_value',
            'icmp_type': 'default_value',
            'position': 'default_value',
            'protocol': 'default_value',
            'source_address_end': 'default_value',
            'source_address_start': 'default_value',
            'source_port_end': 'default_value',
            'source_port_start': 'default_value'
        }
    
        def __init__(self, **kwargs ):
            for key in kwargs:
                valur_or_default = kwargs.get(key, attributes[key])
                setattr(self, key, valur_or_default)
    

    (在生产代码I' d显然添加了更好的错误处理和验证)

1 个答案:

答案 0 :(得分:0)

我会将这些不同的属性组合在"属性集"捆绑它们是有意义的。为参数创建这些集合和手部实例的类。可以测试None值,并且该"属性的默认实例设置"创建和分配。在该实例化期间,您可以同时提供给定对象(服务器,防火墙)的默认参数,但我通常会创建子类来处理该情况并使参数设置显式而不是隐藏在另一个非相关类中。

如果bar1bar2bar3与您相关,那么

 class Bar123:
      def __init__(self, bar1=None, bar2=None, bar3=None):
           self.bar1 = bar1 
           self.bar2 = bar2
           self.bar3 = bar3

 class ServerBar123:
      def __init__(self, bar1=None, bar2=None, bar3=None):
           self.bar1 = bar1 if bar1 else 25
           self.bar2 = bar2 if bar2 else 75
           self.bar3 = bar3

 class ServerFoo:
      def __init__(self, bar123=None, bar2=None, bar3=None, ....):
           self.bar123 = bar123 if bar123 else ServerBar123()
           if self.bar123.bar1 != 25:
               ....