首页 > 解决方案 > 在 Python 中处理许多参数/类属性

问题描述

我正在创建一个 Python 类,它将使用它的参数在这个类中定义另外两个类。例如,ClassA包含ClassBClassC。正因为如此,ClassA有很多参数。

我目前正在使用**kwargsforclassBclassCarguments 解决这个问题,并且只保存参数的输入classA参数。例如:

class A:
    def __init__(self, a1, a2, a3, **kwargs):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3

        # Get B and C kwargs
        default_params = {
            'b1': kwargs.get('b1', 1),
            'b2': kwargs.get('b1', 2),
            'c1': kwargs.get('c1', 1),
            'c2': kwargs.get('c1', 2),          
        }
        for param in default_params:
            self.__dict__[param] = default_params[param]

        B = classB(a1=self.a1, b1=self.b1, b2=self.b2)
        C = classC(a2=self.a2, c1=self.c1, c2=self.c2)

与以下相比,这是一个更糟糕的解决方案吗?

class A:
    def __init__(
        self,
        a1, a2, a3,
        b1, b2, c1, c2):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3
        self.b1 = b1
        self.b2 = b2
        self.c1 = c1
        self.c2 = c2

我担心的是,如果 B 类和 C 类的参数非常多,那么 A 类的属性似乎太多了。另一方面,无论如何,第一种方法似乎占用了更多行。

另一种方法是,如果我只将 kwargs 传递给classBand classC,但是当其中一个类中不存在某些参数时,这将出现错误。

对于具有许多属性并利用这种设计模式的类,是否有一种我在这里看不到的 Pythonic 方式?

标签: pythonoopdesign-patterns

解决方案


您的主要标准应该是避免模仿 Python 本身提供的东西——即参数和默认值,以及实例属性。

由于__init__已经知道它期望的所有属性和默认值(通过default_params),因此直接将它们添加到签名中。避免存储参数 forclassBclassCon A- 如果需要,从实例中获取它们。

class A:
    # handle parameters/defaults natively
    def __init__(self, a1, a2, a3, b1=1, b2=2, c1=1, c2=2):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3
        # do not store B/C attributes, store B/C directly
        self.b = classB(a1=self.a1, b1=b1, b2=b2)
        self.c = classC(a2=self.a2, c1=c1, c2=c2)

这在功能上等同于第一种情况(减去公开所有参数),但使用本机 Python 功能。


如果A必须提供附加功能,请显式添加它们:

  • 如果A应该采用(并忽略)其他参数,请使用额外的catch-all **kwargs

    class A:
        # discard additional parameters/defaults explicitly
        def __init__(self, a1, a2, a3, b1=1, b2=2, c1=1, c2=2, **_):
            ...
    
  • 如果A应该公开classB和/或classC字段,请从实例中提供它们。

    class A:
        ...
    
        @property
        def b1(self):
            return self.b.b1
    

推荐阅读