如何用Python做Obj-C类别?

u0b*_*6ae 9 python

OBJ-C(我没有使用过很长一段时间)有一种叫扩展类.使用新方法声明一个类别并将其编译到您的程序中,该类的所有实例突然拥有新方法.

Python有mixin的可能性,我使用,但mixin必须从程序的底部使用:类必须自己声明它.

预见的类别用例:假设您有一个大的类层次结构,描述了与数据交互的不同方式,声明了获取不同属性的多态方式.现在,类别可以通过在一个位置实现访问这些方法的便捷界面来帮助这些描述类的使用者.(例如,类别方法可以尝试两种不同的方法并返回第一个定义的(非None)返回值.)

有什么办法在Python中做到这一点?

说明性代码

希望这能澄清我的意思.关键是类别就像一个聚合接口,AppObj的使用者可以在代码中进行更改.

class AppObj (object):
  """This is the top of a big hierarchy of subclasses that describe different data"""
  def get_resource_name(self):
    pass
  def get_resource_location(self):
    pass

# dreaming up class decorator syntax
@category(AppObj)
class AppObjCategory (object):
  """this is a category on AppObj, not a subclass"""
  def get_resource(self):
    name = self.get_resource_name()
    if name:
      return library.load_resource_name(name)
    else:
      return library.load_resource(self.get_resource_location())
Run Code Online (Sandbox Code Playgroud)

fra*_*ca7 9

为什么不动态添加方法?

>>> class Foo(object):
>>>     pass
>>> def newmethod(instance):
>>>     print 'Called:', instance
...
>>> Foo.newmethod = newmethod
>>> f = Foo()
>>> f.newmethod()
Called: <__main__.Foo object at 0xb7c54e0c>
Run Code Online (Sandbox Code Playgroud)

我知道Objective-C,这看起来就像是类别.唯一的缺点是你不能对内置或扩展类型这样做.


u0b*_*6ae 4

我想出了这个类装饰器的实现。我使用的是 python2.5,所以我还没有实际使用装饰器语法测试它(这会很好),并且我不确定它的作用是否真正正确。但它看起来像这样:

pycategories.py

"""
This module implements Obj-C-style categories for classes for Python

Copyright 2009 Ulrik Sverdrup <ulrik.sverdrup@gmail.com>
License: Public domain
"""

def Category(toclass, clobber=False):
    """Return a class decorator that implements the decorated class'
    methods as a Category on the class @toclass

    if @clobber is not allowed, AttributeError will be raised when
    the decorated class already contains the same attribute.
    """
    def decorator(cls):
        skip = set(("__dict__", "__module__", "__weakref__", "__doc__"))
        for attr in cls.__dict__:
            if attr in toclass.__dict__:
                if attr in skip:
                    continue
                if not clobber:
                    raise AttributeError("Category cannot override %s" % attr)
            setattr(toclass, attr, cls.__dict__[attr])
        return cls
    return decorator
Run Code Online (Sandbox Code Playgroud)