Obj-C(我很久没有使用过)有一些名为categories的东西来扩展类。使用新方法声明一个类别并将其编译到您的程序中,该类的所有实例突然都有了新的方法。
Python有mixin的可能性,我使用它,但必须在程序的底部使用mixins:类必须自己声明它。
预见类别用例:假设您有一个大的类层次结构,描述了与数据交互的不同方式,声明了获取不同属性的多态方法。现在,类别可以通过在一个位置实现访问这些方法的便捷界面来帮助这些描述类的使用者。 (例如,类别方法可以尝试两种不同的方法并返回第一个定义的(非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())
答案 0 :(得分:9)
为什么不动态添加方法?
>>> class Foo(object):
>>> pass
>>> def newmethod(instance):
>>> print 'Called:', instance
...
>>> Foo.newmethod = newmethod
>>> f = Foo()
>>> f.newmethod()
Called: <__main__.Foo object at 0xb7c54e0c>
我知道Objective-C,这看起来就像是类别。唯一的缺点是你不能对内置或扩展类型这样做。
答案 1 :(得分: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
答案 2 :(得分:1)
Python的setattr
函数使这很容易。
# categories.py
class category(object):
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
# categories_test.py
import this
from categories import category
@category(this)
def all():
print "all things are this"
this.all()
>>> all things are this