1

我希望检查模块中每个函数的参数类型(不使用检查模块)。我自己做过的最简单的解决方案是分别在每个函数中实现检查。

def func1( num1, num2 ):  # the two params must be integers
    if isinstance( num1, int ) and isinstance( num2, int ):
        # ...function code...
        pass
    else:
        return

def func2( float1 ):  # The only param must be float

    if isinstance( float1, float ):
        # ...function code...
        pass
    else:
        return

def func3( str1 ):  # string
    if isinstance( str1, str ):
        # ...function code...
        print 'fdfd'
        pass
    else:
        return


# and, so on ...

但是,想在模块级别做,而不是为每个功能做。每个函数可以有不同的参数。请注意,这不是函数重载。我正在考虑写一个装饰器或一个元类。以下是我在这两种方法中遇到的问题:-

  1. 对所有函数使用通用装饰器:
    在这种方法中,我无法访问每个函数内部定义的实际变量,因此放弃了这个想法。这是我打算写的一个闭包(用作装饰器):
def dec( funcName ):
    def typeChecker():
        i = __import__( __name__ )
        for m in map( lambda x: i.__getattribute__( x ), dir( i ) ):
            if '__call__' in dir( m ):  #Identifying a real function or callable which can be treated as function
                ## Now, that the function is identified, what should I do here to type-check the arguments??
    return typeChecker

请在此处提供一些关于我如何完成这项工作的见解。

2.使用元类创建函数
我只是想知道是否可以使用元类访问发送给函数的参数,然后验证每个参数,然后返回一个全新的类函数对象。但是,不知道该怎么做。这是解决这个问题的好方法吗?

Martijn Peters 给出的 1 个非常好的建议 - 使用注释。Python 2.7 中有什么可以使用的吗?

4

2 回答 2

1

通过装饰器执行此操作相当容易 - 在 Python 2 中,您必须显式装饰每个函数以注释每个参数的类型 - 或者您可以使用文档字符串上的一些标记来使用一些注释,然后调用模块的底部,它将遍历模块上的所有对象,并将装饰器应用于其中定义的每个函数。

在这两种情况下,像这样的装饰器就足够了:

from functools import wraps
from itertools import count

def typechecker(*types, **kw_types):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kw):
            for position, type_, arg in zip(count(), types, args):
                if not isinstance(arg, type_):
                    raise TypeError("Argument in position %s should be a %s"
                                    % (position, type_))
            for key, type_ in kw_types.items():
                if key in kw_types and not isinstance(kw[key], type_):
                    raise TypeError("Argument %s should be a %s"
                                    % (key, type_))
            return func(*args, **kw)
        return wrapper
    return decorator

你可以看到它是这样工作的:

>>> @typechecker(int, int)
... def mysum(a,b):
...    return a + b
... 
>>> mysum(2,3)
5
>>> mysum(2.0,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in wrapper
TypeError: Argument in position 0 should be a <type 'int'>
>>> 
于 2013-04-01T11:04:13.577 回答
-1

我的倾向是这样的:

class A(object):
    def func(self, arg):
        result = self._get_func(arg)(arg)

    def _get_func(self, arg):
        # Create and return the appropriate function here.
        # You have a variety of options, e.g. arg.__class__ (if it exists),
        # or use a bunch of isinstance checks, etc.
        # Please bear in mind that this is really unpythonic!!
        if isinstance(arg, basestring):
            pass

如果您要经常调用该函数,这显然是低效的,因此您需要缓存您的特定函数,并尝试先从缓存中拉取内部_get_func.

def _get_func(self, arg):
    if arg.__class__ in self._cache: # Or whatever
        return self._cache[arg.__class__]
    else:
        pass # Create and return the appropriate function here.

当然,您可以_get_func根据需要覆盖该方法(这应该在模块级别或类级别工作,尽管为了清楚起见我可能更喜欢类)。

另外值得一提的是,这真的很不合常理。如果它们需要做不同的事情,通常只在公开的情况下编写单独的函数,而不是将它们隐藏在函数构造函数中,这通常要干净得多。或者至少,“最好请求原谅”并使用try/except块来封装仅适用于特定类型/类的操作。

于 2013-03-19T19:45:36.900 回答