Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中装饰子类的函数_Python_Python 2.7_Inheritance_Metaclass - Fatal编程技术网

在python中装饰子类的函数

在python中装饰子类的函数,python,python-2.7,inheritance,metaclass,Python,Python 2.7,Inheritance,Metaclass,我认为这是一个非常直截了当的问题,但还没有找到令人满意的答案。简而言之,我希望在父类的子类上强制契约,而不向每个子类添加逻辑。代码示例如下: class A(object): @abc.abstractmethod def do_thing(self, input): raise NotImplementedError class A1(A): def do_thing_decorator(self, do_thing_func):

我认为这是一个非常直截了当的问题,但还没有找到令人满意的答案。简而言之,我希望在父类的子类上强制契约,而不向每个子类添加逻辑。代码示例如下:

class A(object):

    @abc.abstractmethod
    def do_thing(self, input):
        raise NotImplementedError

class A1(A):

    def do_thing_decorator(self, do_thing_func):
        def checked_do_thing(input):
            check = do_thing_func(input)
            if check != 1:
                raise ValueError
            return check
        return checked_do_thing
所以问题是如何自动装饰从
A1
继承的类实现的
do\u thing
函数?假设有一个
A2
类,并且有一个稍微不同的检查


我的初步调查表明,元类是应该采用的方法,但是很难找到它们如何工作的好解释。理想情况下,我正在寻找在python 2.x中运行的东西,但如果只有3.x解决方案,我很乐意更改我的代码库。

首先:您错误地使用了
abc
模块()。你的类
A
应该有
abc.ABCMeta
作为元类。因此,如果您已经在使用一个元类,那么您可以将它扩展到您的优势

继承自abc.ABCMeta的一个元类,用于使
抽象方法
工作并装饰
做事

from abc import ABCMeta, abstractmethod

class DecoratingMeta(ABCMeta):
    def __new__(cls, *args):
        new_class = super(DecoratingMeta, cls).__new__(cls, *args)
        # decorating do_thing manually
        new_class.do_thing = new_class.do_thing_decorator(new_class.do_thing)
        return new_class
class Concrete(Checker):
    def do_thing(self, input):
        return input    # sample implementation
现在,您的抽象基类有一个默认的检查装饰器,它什么也不做:

# class Abstract(metaclass=ABCMeta): in python3
class Abstract(object):
    __metaclass__ = DecoratingMeta  # remove this line in python3
    @abstractmethod
    def do_thing(self, input):
        pass

    @classmethod
    def do_thing_decorator(cls, function):
        return function     # default decorator that does nothing
注意,在这种情况下,
do\u thing\u decorator
必须是类方法。 有关在
python3
python2
中工作的元类,请参阅

仅实现特定检查器但仍然是抽象的检查器类:

class Checker(Abstract):
    @classmethod
    def do_thing_decorator(cls, function):
        def do_checked_thing(self, input):
            check = function(self, input)  # NOT self.do_thing(input) else recursion error
            if check != 1:
                raise ValueError("Check failed")
            return check
        return do_checked_thing
请注意,您编写的
check=do\u thing\u func(输入)
行将导致递归错误

以及您的具体类,以及
do_thing
的示例实现:

from abc import ABCMeta, abstractmethod

class DecoratingMeta(ABCMeta):
    def __new__(cls, *args):
        new_class = super(DecoratingMeta, cls).__new__(cls, *args)
        # decorating do_thing manually
        new_class.do_thing = new_class.do_thing_decorator(new_class.do_thing)
        return new_class
class Concrete(Checker):
    def do_thing(self, input):
        return input    # sample implementation
您可以验证
do\u thing(1)
成功和
do\u thing(2)
失败

c = Concrete()

c.do_thing(1)
try:
    c.do_thing(2)
except ValueError:
    print("check failed")
这种方法的缺点是不能将
do\u thing\u decorator
抽象化

这已经是很多文本了,但是如果你根本不想使用任何元类,有一个更简单的方法:

编写一个类,使用两个“抽象”方法在
do\u thing
方法中执行检查:

请注意,
do\u thing\u func
check\u do\u thing
并不是真正的抽象对象,您仍然可以实例化类型为
abstract
的对象。如果您需要它们是抽象的,请在此处使用标准的
abc.ABCMeta
meta类

现在创建一个checker类,它实现了
check\u do\u thing

class Checker(Abstract):
    def check_do_thing(self, result):
        if result != 1:
            raise ValueError("check failed")
这变得简单多了,因为我们这里不需要装饰师

最后是实现
do\u thing\u func

class Concrete(Checker):
    def do_thing_func(self, input):
        return input    # sample implementation
请注意,
Concrete
现在必须实现
do\u thing\u func
,但当您使用该类时,必须调用
do\u thing


这里的缺点是,您仍然可以覆盖
do\u thing
,从而破坏检查。

首先:您错误地使用了
abc
模块()。你的类
A
应该有
abc.ABCMeta
作为元类。因此,如果您已经在使用一个元类,那么您可以将它扩展到您的优势

继承自abc.ABCMeta的一个元类,用于使
抽象方法
工作并装饰
做事

from abc import ABCMeta, abstractmethod

class DecoratingMeta(ABCMeta):
    def __new__(cls, *args):
        new_class = super(DecoratingMeta, cls).__new__(cls, *args)
        # decorating do_thing manually
        new_class.do_thing = new_class.do_thing_decorator(new_class.do_thing)
        return new_class
class Concrete(Checker):
    def do_thing(self, input):
        return input    # sample implementation
现在,您的抽象基类有一个默认的检查装饰器,它什么也不做:

# class Abstract(metaclass=ABCMeta): in python3
class Abstract(object):
    __metaclass__ = DecoratingMeta  # remove this line in python3
    @abstractmethod
    def do_thing(self, input):
        pass

    @classmethod
    def do_thing_decorator(cls, function):
        return function     # default decorator that does nothing
注意,在这种情况下,
do\u thing\u decorator
必须是类方法。 有关在
python3
python2
中工作的元类,请参阅

仅实现特定检查器但仍然是抽象的检查器类:

class Checker(Abstract):
    @classmethod
    def do_thing_decorator(cls, function):
        def do_checked_thing(self, input):
            check = function(self, input)  # NOT self.do_thing(input) else recursion error
            if check != 1:
                raise ValueError("Check failed")
            return check
        return do_checked_thing
请注意,您编写的
check=do\u thing\u func(输入)
行将导致递归错误

以及您的具体类,以及
do_thing
的示例实现:

from abc import ABCMeta, abstractmethod

class DecoratingMeta(ABCMeta):
    def __new__(cls, *args):
        new_class = super(DecoratingMeta, cls).__new__(cls, *args)
        # decorating do_thing manually
        new_class.do_thing = new_class.do_thing_decorator(new_class.do_thing)
        return new_class
class Concrete(Checker):
    def do_thing(self, input):
        return input    # sample implementation
您可以验证
do\u thing(1)
成功和
do\u thing(2)
失败

c = Concrete()

c.do_thing(1)
try:
    c.do_thing(2)
except ValueError:
    print("check failed")
这种方法的缺点是不能将
do\u thing\u decorator
抽象化

这已经是很多文本了,但是如果你根本不想使用任何元类,有一个更简单的方法:

编写一个类,使用两个“抽象”方法在
do\u thing
方法中执行检查:

请注意,
do\u thing\u func
check\u do\u thing
并不是真正的抽象对象,您仍然可以实例化类型为
abstract
的对象。如果您需要它们是抽象的,请在此处使用标准的
abc.ABCMeta
meta类

现在创建一个checker类,它实现了
check\u do\u thing

class Checker(Abstract):
    def check_do_thing(self, result):
        if result != 1:
            raise ValueError("check failed")
这变得简单多了,因为我们这里不需要装饰师

最后是实现
do\u thing\u func

class Concrete(Checker):
    def do_thing_func(self, input):
        return input    # sample implementation
请注意,
Concrete
现在必须实现
do\u thing\u func
,但当您使用该类时,必须调用
do\u thing


这里的缺点是,您仍然可以覆盖
do\u thing
,从而破坏检查。

您是否看过
\u新的方法?
方法?@IgnacioVazquez Abrams不是一个不合理的解决方案。我希望在方法层面上有一些更直观的东西,但如果我找不到更好的东西,我可能会默认。你看过
\uuuuu new\uuuu()
方法吗?@IgnacioVazquez Abrams不是一个不合理的解决方案。我希望在方法层面上有一些更直观的东西,但如果找不到更好的东西,我可能会默认为这样。