python27:如何修复/存储方法的值以保留其接口?

2024-10-02 22:28:45 发布

您现在位置:Python中文网/ 问答频道 /正文

如果所有的东西都是python中的对象,那么为什么下面的方法不起作用?你知道吗

class Hello(object):

    def hello(self):
        print(x)

h = Hello()
h.hello.x = "hello world"

当我这样做时,我得到:

AttributeError: 'instancemethod' object has no attribute 'value'

我能做到这一点的一种方法是使用partial,但是我不确定这会对一个对象产生什么影响。有没有别的方法可以达到这个目的?你知道吗

from functools import partial
class Hello(object):

    def hello(self, x):
        print(x)

h = Hello()
newMethod = partial(h.hello, "helloworld")
newMethod()

好的,从下面的评论来看,人们想要一个“真实”的场景一个例子可以被认为是如下所示:

file.txt contains the following list
["ItemID1", "ItemID2", "ItemID3", "ItemID4"]

def BindMethods(self):
    # ["ItemID1", "ItemID2", "ItemID3", "ItemID4"]
    items = readFromFile("file.txt")
    self.bind(AN_EVENT, GenericMethod)

 def GenericMethod(self, i, event):
     # The person calling this method knows that the method
     # only accepts a single argument, not two.
     # I am attempting to preserve the interface which I do not have control over
     data = generateDataFromID(i)
     table[i] = data

这里的想法是将一个方法绑定到一个事件,调用方希望该方法具有特定的签名,即单个输入参数。你知道吗

但是在绑定的时候,您需要将一些额外的信息传递给处理程序。你不知道你要传递多少信息,因为它是可变的。你知道吗

同一事物的扩展/编译时版本如下:

file.txt contains the following list
["ItemID1", "ItemID2", "ItemID3", "ItemID4"]

def BindMethods(self):
    # ["ItemID1", "ItemID2", "ItemID3", "ItemID4"]
    items = readFromFile("file.txt")
    self.bind(AN_EVENT, self.Item1Method)
    self.bind(AN_EVENT, self.Item2Method)
    self.bind(AN_EVENT, self.Item3Method)
    ......

 def Item1Method(self, event):
     data = generateDataFromID("Item1")
     table["Item1ID"] = data

 def Item2Method(self, event):
     data = generateDataFromID("Item2")
     table["Item2ID"] = data

Tags: the方法selftxtanhellodatabind
3条回答

在你编辑之后,我觉得这好像你在寻找一种可能性,把某些事件路由到某些函数,对吧?你知道吗

与其将新属性绑定到现有的实例方法,不如考虑建立一个干净的、可扩展的事件路由系统。你知道吗

基本路由核心

虽然通常应用singleton模式总是一个很好的点来问自己是否遵循了正确的概念,但在这里它是完全有意义的。路由的核心与此类似:

def singleton(cls):
    instance = cls()
    instance.__call__ = lambda: instance
    return instance

@singleton
class EventRouter(object):
    def __init__(self):
        self._routes = dict()

    def bind(self, key, func):
        self._routes[key] = func

    def route(self, key):
        if key in self._routes.keys():
            return self._routes[key]()
        else:
            raise KeyError('Unbound routing key: {}'.format(key))

EventRouter是一个单例类,它可以将函数绑定到某些键,并且还可以将发生的事件路由到它们所需的目标函数。
现在可以在运行时将事件绑定到所需函数:

def my_event_function():
    print('An event was handled.')

EventRouter.bind('E_MYEVT', my_event_function)

# If you are iterating over events (for example drawn from a file),
# you can direct them to their functions:
for e in ['E_MYEVT', 'E_WHATEVT', 'E_NOEVT']:
    EventRouter.route(e)

路由装饰器

如果需要,可以设置另一个装饰器,用于将方法直接绑定到特定事件类型:

def eventroute(key):
    def register_method(call):
        EventRouter.bind(key, call)
    return register_method

@eventroute('E_MYEVT')
def handle_myevt():
    print('Handling event: E_MYEVT')

@eventroute('E_WHATEVT')
def handle_whatevt():
    print('Handling event: E_WHATEVT')

if __name__ == '__main__':
    for e in ['E_MYEVT', 'E_WHATEVT']:
        EventRouter.route(e)

>>> Handling event: E_MYEVT
>>> Handling event: E_WHATEVT

向路由端点传递参数

如果要将参数传递给端点,只需在转发调用时通过可选的关键字参数**kwargs扩展调用:

EventRouter类中,将route方法更改为:

def route(self, key, **kwargs):
    if key in self._routes.keys():
        return self._routes[key](**kwargs)
    else:
        raise KeyError('Unbound routing key: {}'.format(key))

对于端点,设置所需的参数。在本例中,我使用参数filename

@eventroute(...)
def handle_...(filename):
    print('Handling event: ...')
    print(filename)

在分派事件时,请提供所需的参数kwarg:

events = ['E_MYEVT', 'E_WHATEVT']
for e in events:
    EventRouter.route(e, filename='whatever.jpg')

>>> Handling event: E_MYEVT
>>> whatever.jpg
>>> Handling event: E_WHATEVT
>>> whatever.jpg

去哪里

这只是一个非常基本的设置的简要概述。
您可以将EventRouter扩展为任意复杂,例如,在多层层次结构中添加路由密钥,等等。此外,还可以向方法中添加更多参数。您甚至可以考虑扩展eventroute修饰符来定义传递给端点函数的kwargs,以使函数签名尽可能通用。你知道吗

可能看起来有点过分,但这样的结构非常简洁,任何导入您的库/脚本并希望为单个事件添加自己的端点的人都可以对其进行扩展。你知道吗

这个答案指的是编辑之前的问题;它可能不再合适了。

实际上,这个问题是有解决办法的。在Python3中,可以直接将属性分配给绑定方法,而在Python2.7中,这并不是那么简单。你知道吗

看看这样的类定义:

class Hello(object):
    def hello(self):
        print(self.hello.x)

在常规使用中(实例化并随后调用实例方法hello()),由于缺少属性x,实现将失败:

h = Hello()
h.hello()

>>> AttributeError: 'function' object has no attribute 'x'

将代码稍微更改(警告:破解)如下:

class Hello(object):
    def hello(self):
        if not hasattr(self.hello, 'x'):
            self.hello.__dict__['x'] = 0
        print(self.hello.x)

将允许您像往常一样使用类实现:

h = Hello()
h.hello()

>>> 0

print(h.hello.x)

>>> 0

因此,您可以将属性绑定到绑定的方法,但是您尝试的方式只适用于python3。你知道吗

不管这对你有什么好处,你可能会想问问自己,这是否是实现所需行为的最佳方式。

第一个版本中的x没有定义:按照编写代码的方式,它应该是一个全局变量;按照使用它的方式,它应该是对象的一个属性。你想做点像

class Hello(object):
    def __init__(self, x):
        self.x = x

    def hello(self):
        print(self.x)

h = Hello("Hello World")

相关问题 更多 >