【问题标题】:Python object methods dictPython对象方法字典
【发布时间】:2011-12-24 12:14:26
【问题描述】:

我需要一个类实例变量,其中包含处理程序列表(此类实例的指定方法)。处理程序列表可根据要求提供。

我有两个解决方案,但没有一个不适合我。

  1. http://www.ideone.com/3aSkT - 你会得到一个循环引用。 GC 可以清理它,但我们不知道什么时候。
  2. http://www.ideone.com/OaP5c - 在这里,当您调用时,您需要将类的实例显式传递给函数。

还有其他建议吗?

【问题讨论】:

  • 我更改了问题以便更好地理解。
  • 你为什么担心循环引用? Python 会为你处理好它。
  • 为什么不用方法名呢?你想解决什么问题?
  • ideone.com/rztZT 进一步推进

标签: python methods dictionary


【解决方案1】:

如果我没听错,您可以简单地使用内置函数dir()。示例:

>>> class Foo(object):
...     def m1(self):
...         pass
...     def m2(self):
...         pass
... 
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm1', 'm2']
>>> [m for m in dir(Foo) if '__' not in m]
['m1', 'm2']

编辑:您的问题和您的 cmets 并不是很清楚。如果您可以编辑提及预期结果的问题,这将有所帮助。我最好的猜测是,在下面阅读您的评论(“我需要这本字典 {int type: method type})可能是您想要的:

>>> dict(enumerate([getattr(Foo, m) for m in dir(Foo) if '__' not in m]))
{0: <unbound method Foo.m1>, 1: <unbound method Foo.m2>}

EDIT2:查看您最新的 pastebin,当您编写时:

packet_ids_to_check_up = (0x0404, 0x0405, 0x0404, 0x0505, 0x0506)
    for packet_id in packet_ids_to_check_up:
        if packet_id in some_class_obj:
            some_class_obj[packet_id]('Hello world')

您似乎希望您的班级充当字典。如果是这种情况,您可能应该查看collections.abc 模块,尤其是MutableMapping 类。来自python glossary

ma​​pping - 支持任意键查找并实现 Mapping 或 MutableMapping 抽象基类中指定的方法的容器对象。示例包括 dict、collections.defaultdict、collections.OrderedDict 和 collections.Counter。

这意味着实现以下方法:

  • __contains__
  • keys
  • items
  • values
  • get
  • __eq__
  • __ne__
  • pop
  • popitem
  • clear
  • update
  • setdefault

但是,从您的代码来看,为什么您不能只使用简单的字典(或最终直接继承 dict...),这并不是不言而喻的。

这有帮助吗?

【讨论】:

  • 这将只保留所需方法的名称,但不保留对象。我需要有这本字典 {int type: method type}
  • @Miatar - 查看我的编辑。如果我仍然没有猜到,请发表评论。 :)
  • 不行,键值不一致。我想是时候说我正在为 MMO 写一个机器人了,在这种情况下,关键是数据包的标识符。
  • @Miatar - 我查看了您发布的最后一个粘贴箱:我的答案中有更多编辑。
  • 主要问题不在于容器的选择,而是如果我们将对象方法保留在对象中,它会创建一个循环引用,并且不允许对象被引用计数破坏,当我们离开范围时。有时它非常重要。
【解决方案2】:

我不确定是否理解您的问题,但是如果您想将方法名称“映射”到其他方法(调用 Foo().store() 实际上会调用 Foo().someMethod())而不引用它们,您可以通过覆盖默认object.__getattribue__ 行为。

class Foo(object):
    mapping = {'store': 'someMethod'}

    def __getattribute__(self, attr):
        try:
            # first check if it's a "regular" attribute/method
            return super(Foo, self).__getattribute__(attr)
        except AttributeError:
            # attribute was not found, if it's not in your mapping, re-raise the error
            if attr not in self.mapping:
                raise
            mapped_attr = self.mapping[attr]
            return super(Foo, self).__getattribute__(mapped_attr)

    def someMethod(self):
        print "Foo().someMethod()"

foo = Foo()
foo.store()

输出:

>>> Foo().someMethod()

【讨论】:

  • 出于重构原因,我不想将方法名称存储在文本中。
【解决方案3】:

考虑到 OP 要求一个类实例变量并且他还可能想要获取有关“私有”方法的信息,扩展 @mac 的答案:

In [5]: class Foo(object):
   ...:     def m1(self):pass
   ...:     def m2(self):pass
   ...:
In [6]: f = Foo()
In [7]: lst = dir(f)
In [8]: [m for m in lst if not m.endswith('__')]
Out[8]: ['m1', 'm2']

如果你想要对象方法:

In [17]: getattr(Foo, 'm1')
Out[17]: <unbound method Foo.m1>

或直接在实例的列表推导中:

In [18]: [getattr(f, m) for m in lst if not m.endswith('__')]
Out[18]:
[<bound method Foo.m1 of <__main__.Foo object at 0x00000000073DD1D0>>,
 <bound method Foo.m2 of <__main__.Foo object at 0x00000000073DD1D0>>]

编辑:因此,鉴于您在链接中提供的示例,也许您正在寻找类似的内容:

class SomeClass:

    store = {0: 'someMethod', 1: 'someMethod1'}

    def __init__(self):
        print('__init__')

    def __del__(self):
        print('__del__')

    def get_dict(self):
        return [getattr(self, att) for idx, att in SomeClass.store.items()]

    def someMethod(): pass
    def someMethod1(): pass


f = SomeClass()
print f.get_dict()

打印出来的:

__init__
[<bound method SomeClass.someMethod of <__main__.SomeClass instance at 0x0000000
0026E2E08>>, <bound method SomeClass.someMethod1 of <__main__.SomeClass instance
 at 0x00000000026E2E08>>]
__del__

【讨论】:

  • 感谢 getattr,但这仍然不能回答我的问题。
  • 那意味着我无法理解你的问题。你能澄清一下吗?也许你可以举例说明你想得到什么以及你想如何要求它?这会有所帮助。
猜你喜欢
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多