使用其他类的默认初始化值

时间:2020-03-31 13:59:15

标签: python python-3.x

我有2个具有某些功能的类:

class A:
   def __init__(self, one=1, two=2):
      self.one = one
      self.two = two

   def do_smt(self):
      ...

class B:
   def __init__(self, value="test"):
      self.value = value

   def do_smt(self):
      ...

我有一个第三类,必须使用这两个类。

class C:
   def __init__(self, one=1, two=2, value="test"):
      self.A = A(one, two)
      self.B = B(value)

   def do_smt(self):
      ...

现在我这样做:new_class = C()

但是如果class A or B的默认值更改了,那我还需要在class C中更改它。是否可以通过一种方式知道自己的默认参数来写class C?它不需要处理任何参数,也不需要处理其他类期望的参数。

5 个答案:

答案 0 :(得分:1)

您可以使用inspect.signature获取类__init__的每个“基础”类的C方法的参数,并让C.__init__接受可变关键字参数,因此它可以遍历“基”类,并传递给每个__init__方法,只需要它以及给定关键字参数具有什么。使用itertools.islice忽略第一个参数,该参数始终为self

import inspect
from itertools import islice

class C:
    bases = A, B
    params = {}
    for cls in bases:
        params[cls] = inspect.signature(cls.__init__).parameters

    def __init__(self, **kwargs):
        for cls in self.bases:
            setattr(self, cls.__name__, cls(**{key: kwargs[key] for key in 
                islice(self.params[cls], 1, None) if key in kwargs}))

这样:

c = C(one=3,value='hi')
print(c.A.one)
print(c.A.two)
print(c.B.value)

输出:

3
2
hi

答案 1 :(得分:0)

您可以使用一些哨兵值(此处为None),并且仅在提供有意义的参数时才传递参数:

class C:
   def __init__(self, one=None, two=None, value=None):
      if one is two is None:
          self.A = A()
      else:
          self.A = A(one, two)
      if value is None:
          self.B = B()
      else:
          self.B = B(value)

这样,AB的默认值可以照顾自己。

答案 2 :(得分:0)

在调用类A和B之前,为变量定义初始化值

尝试在C类init调用之前添加这些内容:

self.initA_one = A.one
self.initA_two = A.two
self.initB_value = B.value

并继续

self.A = A (.,.)
self.B = B (.)

编辑:

这就是我的意思。

class C():
   def __init__(self, one=-1, two=-2, value="detest"):
      self.initA_one = A().one
      self.initA_two = A().two
      self.initB = B().value
      self.A = A(one, two)
      self.B = B(value)

   def do_smt(self):
      print()

new_class = C()

print(f'default A.one is {new_class.initA_one}, new value A.one is {new_class.A.one}.')
print(f'default A.two is {new_class.initA_two}, new value A.two is {new_class.A.two}.')
print(f'default B.value is {new_class.initB}, new B.value is {new_class.B.value}')

给予

default A.one is 1, new value A.one is -1.
default A.two is 2, new value A.two is -2.
default B.value is test, new B.value is detest

答案 3 :(得分:0)

一种解决方案是将默认值分解为常量:

DEFAULT_ONE = 1
DEFAULT_TWO = 2

class A:
   def __init__(self, one=DEFAULT_ONE, two=DEFAULT_TWO):
      pass

也使用class C中的常量。

答案 4 :(得分:0)

我不确定这是否完全符合您的要求,但是基本上,您可以让C决定给A,B的内容,然后让A,B使用A和B中的**kwds方法参数来决定使用什么。 B。

与示例类C2的区别之一是,如果C具有不同的默认值,它将覆盖A,B。

在C3下,还有另一种选择,您可以使用保护值(不使用None来使它成为默认值)仅传递给C3的参数。

class A:
   def __init__(self, one=1, two=2, **kwds):
      self.one = one
      self.two = two

   def do_smt(self):
      pass

class B:
   def __init__(self, value="test", **kwds):
      self.value = value


class C:
   def __init__(self, one=1, two=2, value="test"):
      self.A = A(one, two)
      self.B = B(value)


class C2:
    """ your default values override those of A, B"""

    def __init__(self, one=1, two=2, value="test"):
      locals_ = locals()
      locals_.pop("self")

      self.A = A(**locals_)
      self.B = B(**locals_)


undefined = NotImplemented

class C3:
    """ your default values dont affect A and Bs"""

    def __init__(self, one=undefined, two=undefined, value="test"):


      locals_ = {k:v for k,v in locals().items() if k != "self" and v is not undefined}

      self.A = A(**locals_)
      self.B = B(**locals_)

      #can still use it locally
      self.one = one if one is not undefined else 11
      self.two = two if two is not undefined else 22




c= C()

print("c.A.one:", c.A.one)
print("c.B.value:", c.B.value)

c2= C2()

print("c2.A.one:", c2.A.one)
print("c2.B.value:", c2.B.value)


c3= C3()

print("c3.A.one:", c3.A.one)
print("c3.one:", c3.one)
print("c3.B.value:", c3.B.value)

输出:

c.A.one: 1
c.B.value: test
c2.A.one: 1
c2.B.value: test
c3.A.one: 1
c3.one: 11
c3.B.value: test

您甚至可以使用C的变体,使其本身使用**kwds并将它们传递给A,B,以防他们在其中找到价值。

class C4:
    """ your default values dont affect A and Bs 
        and you can pass in anything.  
       Neither two or value are known to C and that's OK"""

    def __init__(self, one=undefined, **kwds):
      locals_ = locals()

      locals_ = {k:v for k,v in locals().items() if k not in ("self","kwds") and v is not undefined}

      locals_.update(**kwds)

      self.A = A(**locals_)
      self.B = B(**locals_)

      #can still use it locally
      self.one = one if one is not undefined else 11


c4= C4(value="somevalue")

print("c4.A.one:", c4.A.one)
print("c4.A.two:", c4.A.two)
print("c4.one:", c4.one)
print("c4.B.value:", c4.B.value)

输出:

c4.A.one: 1
c4.A.two: 2
c4.one: 11
c4.B.value: somevalue