针对动态创建的对象进行类型检查

Type checking against dynamically created objects

我想对方法的输入和输出执行一些动态类型检查。我想出的解决方案如下。基本上,在超类的 __init__ 函数中,我通过对输入和输出进行一些动态类型检查来更新子类方法。请注意,类型检查应基于用户在实例化期间定义的属性 (AlgorithmAttribute)。我想知道是否有更好的解决方案。

import abc
import six
import attr
from typing import Dict, Text

@attr.s
class AlgorithmAttribute(object):
  inputs = attr.ib(type=Dict[Text, int])
  outputs = attr.ib(type=Dict[Text, int])

class BaseHandler(six.with_metaclass(abc.ABCMeta, object)):
  def __init__(self, alg):
    self.alg = alg
    self.out = self.__getattribute__('prepare')
    self.__setattr__('prepare', self.temp)

  def temp(self, a, b):
    result = self.out(a, b)
    # Verifies inputs.
    if set(a.keys()) == set(self.alg.inputs.keys()):
      print('Inputs correct!')
    # Verifies outputs.
    if set(result.keys()) == set(self.alg.outputs.keys()):
      print('Outputs correct!')
    return result

  @abc.abstractmethod
  def prepare(self, a):
    pass


class SubHandler(BaseHandler):
    def __init__(self, alg):
      super(SubHandler, self).__init__(alg)

    def prepare(self, a:Dict[Text, int], b:Dict[Text, int]) -> Dict[Text, int]:
        return {'c': 33}


alg = AlgorithmAttribute(inputs={'a': 2, 'b': 3}, outputs={'c': 10})
sh = SubHandler(alg)
sh.prepare({'a': 20, 'b': 200}, b={'c': 20, 'd': 200})

我不是很清楚为什么你要验证 prepare() 的第一个参数反对 inputs 或者将带有未使用值的字典传递给 AlgorithmAttribute 有什么意义,但更多在我看来,Pythonic 方式是放弃 类 并使用 decorator:

from dataclasses import dataclass
from typing import Dict, Text

@dataclass
class AlgorithmAttribute(object):
    inputs: Dict[Text, int]
    outputs: Dict[Text, int]

def validate_inputs_outputs(validation_params: AlgorithmAttribute):
    def wrap(func):
        def wrapped_func(*args, **kwargs):
            result = func(*args, **kwargs)
            # Verifies inputs.
            if set(args[0].keys()) == set(validation_params.inputs.keys()):
                print('Inputs correct!')
            # Verifies outputs.
            if set(result.keys()) == set(validation_params.outputs.keys()):
                print('Outputs correct!')
            return result
        return wrapped_func
    return wrap

@validate_inputs_outputs(AlgorithmAttribute(inputs={'a': 2, 'b': 3}, outputs={'c': 10}))
def prepare(a:Dict[Text, int], b:Dict[Text, int]) -> Dict[Text, int]:
    return {'c': 33}

prepare({'a': 20, 'b': 200}, b={'c': 20, 'd': 200})