2009-08-20 15 views
9

Obj-C (que no he usado durante mucho tiempo) tiene algo llamado categories para extender las clases. Al declarar una categoría con nuevos métodos y compilarla en su programa, todas las instancias de la clase de repente tienen los nuevos métodos.¿Cómo hacer categorías Obj-C en Python?

Python tiene posibilidades de mixin, que yo uso, pero las mixins deben usarse desde la parte inferior del programa: la clase tiene que declararse por sí misma.

Caso de uso de categorías previstas: Supongamos que tiene una gran jerarquía de clases que describe diferentes formas de interactuar con datos, declarando formas polimórficas para obtener diferentes atributos. Ahora, una categoría puede ayudar al consumidor de estas clases descriptivas mediante la implementación de una interfaz conveniente para acceder a estos métodos en un solo lugar. (Un método de categoría podría, por ejemplo, probar dos métodos diferentes y devolver el primer valor de retorno definido (distinto de Ninguno).

¿Alguna forma de hacerlo en Python?

código ilustrativo

I esperanza que esto aclare a qué me refiero. El punto es que la Categoría es como una interfaz agregada, que el consumidor de AppObj puede cambiar en su código.

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

En su ejemplo, le instanciar AppObj o AppObjCategory? BTW Python tiene decoradores de clase ahora en 2.6: http://docs.python.org/whatsnew/2.6.html#pep-3129-class-decorators –

+0

I instancia de AppObj (y subclases de los mismos). El código de Categoría puede estar completamente separado (es decir, AppObj puede estar en una biblioteca, la Categoría en la aplicación). – u0b34a0f6ae

+0

Quizás solo sea un caso para implementar el decorador de la categoría Category en ese momento; copie todos los atributos de la Categoría a la clase base, omitiendo algunos atributos como ... __doc__ y __dict__? – u0b34a0f6ae

Respuesta

2

Se me ocurrió esta implementación de un decorador de clases. Estoy usando python2.5, así que no lo he probado con la sintaxis del decorador (lo que sería bueno), y no estoy seguro de qué es realmente correcto. Pero parece que esto:

pycategories.py función

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

Copyright 2009 Ulrik Sverdrup <[email protected]> 
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 
8

¿Por qué no simplemente agrega métodos dinámicamente?

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

Sé Objective-C y esto se parece a categorías. El único inconveniente es que no puede hacer eso con los tipos integrados o de extensión.

+1

única diferencia es que la categoría es más sistemática o explícita, especialmente si ya conoce el concepto. – u0b34a0f6ae

+0

Me gustaría agregar este pequeño fragmento de ayuda relacionada: puede obtener las superclases de un objeto usando '__class __.__ mro__' en ese objeto. Esto puede ser útil si tiene múltiples clases a las que desea agregar el método y está buscando su superclase común. – ArtOfWarfare

2

de Python setattr lo hace fácil.

# 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 
Cuestiones relacionadas