Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.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 如何使用decorator将函数绑定到对象实例?_Python_Python 3.x_Decorator - Fatal编程技术网

Python 如何使用decorator将函数绑定到对象实例?

Python 如何使用decorator将函数绑定到对象实例?,python,python-3.x,decorator,Python,Python 3.x,Decorator,我正在尝试将函数绑定到对象实例。例如,我有一个对象,我试图将一个函数绑定到condition属性。 问题是我想用一个装饰师来做这件事: class Transition(object): def __init__(self, enter, exit, condition=None): if not isinstance(enter, State) or not isinstance(exit, State): raise TypeError("Pa

我正在尝试将函数绑定到对象实例。例如,我有一个对象,我试图将一个函数绑定到condition属性。 问题是我想用一个装饰师来做这件事:

class Transition(object):
    def __init__(self, enter, exit, condition=None):
        if not isinstance(enter, State) or not isinstance(exit, State):
            raise TypeError("Parameters should be an instance of the State class")
        self.enter = enter
        self.exit = exit
        self.condition = None
        self.effect = None

    def __repr__(self):
        print("Going from {} to {} with condition {} and effect {}".format(self.enter, self.exit, self.condition.__name__, self.effect.__name__)) 

    def __eq__(self, other):
        return self.enter == other.enter and self.exit == other.exit

    def is_enpoint(self, endpoints):
        """
        :parameter --> 'endpoints' is a tuple indicating where the transition flows(from, to) 
        :return --> boolean
        :description --> check if the given endpoints are valid 
        """
        return self.enter == endpoints[0] and self.exit == endpoints[1]
然后我将一个函数绑定到对象的实例

@bind
my_condition():
    return True
在此之后,如果我们查看对象的实例条件属性,我们应该有一个对给定函数的引用

编辑1:
f实例应该有一个对条件1函数的引用,而f2实例应该有一个对条件属性的条件2的引用,我在这里只是猜测,但是您可以使用修饰符将函数绑定到类,例如:

class Foo:
    pass

def bind(fn):
    setattr(Foo, fn.__name__, fn)
    return fn

@bind
def bar(self):
    return 7
用法:

>>> f = Foo()
>>> f.bar()
7
@bind(Foo)
def bar(self):
    return 7

@bind(Foo)
@property
def bat(self):
    import random
    return random.randint(1, 6)

>>> f = Foo()
>>> f.bar()
7
>>> f.bat
4

支持属性和绑定到自定义类的更高级示例:

def bind(cls):
    def decorator(fn):
        name = fn.fget.__name__ if isinstance(fn, property) else fn.__name__
        setattr(cls, name, fn)
        return fn
    return decorator
用法:

>>> f = Foo()
>>> f.bar()
7
@bind(Foo)
def bar(self):
    return 7

@bind(Foo)
@property
def bat(self):
    import random
    return random.randint(1, 6)

>>> f = Foo()
>>> f.bar()
7
>>> f.bat
4

最后,您绝对不应该使用的解决方案,但我无法阻止自己:

from functools import partial

def bind(clsname, first, second=None):
    if second is None:  # class binding
        cls = globals()[clsname]
        fn = first
        name = fn.fget.__name__ if isinstance(fn, property) else fn.__name__
        setattr(cls, name, fn)
    else:  # instance binding
        self = first
        fn = second
        name = fn.fget.__name__ if isinstance(fn, property) else fn.__name__
        setattr(self, name, partial(fn, self))

class BindableMeta(type):
    def __new__(cls, name, bases, dct):
        def inner(*args):
            return bind(name, *args)
        dct["bind"] = inner
        return type.__new__(cls, name, bases, dct)


class Bindable(metaclass=BindableMeta):
    pass

class Foo(Bindable):
    pass

f = Foo()
g = Foo()


@Foo.bind
def bar(self):
    return 5

@f.bind
def bat(self):
    return 5

@Foo.bind
@property
def prop(self):
    return 5


assert f.bar() == 5
assert f.bat() == 5
try:
    assert g.bat() == 5
except AttributeError:
    pass
else:
    raise RuntimeError("shouldn't work")
assert f.prop == 5

当然,decorator必须将它要绑定到的实例作为一个参数,而且,如果修饰函数本身也有一个参数作为它绑定的实例传递,那么代码将更干净:如果它被定义为一个方法,则相当于
self
。Python不会自动插入它,但它可能被称为
self
,因此易于阅读

class Transition:
   ...

f = Transition

def bind(instance):
    def decorator(func):
        def wrapper (*args, **kwargs):
              return func(instance, *args, **kwargs)
        setattr(instance, func.__name__, wrapper)
        return wrapper
    return decorator

@bind(f)
def condition(self, ...):
    ...
如果您想要一个更扁平的装饰器,您可以使用
functools.partial
-然后我也使用
functools.wrapps
,因为优秀的装饰器无论如何都应该使用它:

import functools

...

def bind(func, instance=None):
    if instance is None:
         return functools.partial(bind, instance=func)
    @functools.wraps(func)
    def wrapper(*args, **kw):
         return func(instance, *args, **kw)
    setattr(instance, func.__name__, wrapper)
    return wrapper

这是因为在Python中,当一个函数直接归属于一个实例时,它的行为与任何普通属性完全相同:Python将检索该函数,然后调用它,不做任何修改——不将其更改为方法,也不插入
self
参数)。我们通过将实例作为非局部变量保存在decorator代码中来实现这一点。

我想我以前写过一篇关于类似问题的博客文章。它解释了如何将两个python类属性绑定在一起,以便更新一个属性会自动更新另一个属性。我举例说明了解决这个问题的两种可能的方法。第一个是解释在博客文章与实际例子。您可能还计划将文章中所述的概念用于其他目的。

您的问题不清楚。。。您希望所有其他对象正常地查找其属性,但一个特定对象应该为其使用属性/函数?为什么要使用decorator语法呢?是否要将此函数作为该类中的方法?您如何定义该属性?欢迎使用SO。恐怕你的问题不是一个真正的问题-你说了你想做什么,但你没有解释你的实际问题是什么。请注意,如果问题是“如何做到这一点”,你应该先自己尝试一下。我也在网上搜索了答案,但没有找到。@AlexandreManeta“你做了”什么?解释你的实际问题?很抱歉,您没有这样做-您的帖子中完全没有提到您为实现您的功能所做的工作,也没有提到您遇到的问题。您可能需要阅读帮助部分,特别是这个:和这个:这适用于Foo类的每个实例,还是只适用于Foo类的一个实例。例如,如果您有一个f变量和一个f1,它们是否都将此函数作为attribute@AlexandreManeta我添加了一个更通用的版本。@AlexandreManeta这适用于Foo类的每个实例。如果您希望它只应用于一个实例,那么您需要以某种方式告诉装饰程序该实例是哪个实例(属性根本不起作用)。您的第一个示例几乎也适用于实例-您可以在实例上设置属性,就像这样。所缺少的只是告诉函数在运行时它也绑定了实例的方法。(Python通过插入
self
参数所做的事情)@jsbueno
setattr(实例,fn.\uuuuu name\uuuuuuuuuuu,functools.partial(fn,实例))
将起到一定的作用