2009-08-20 8 views
9

Obj-C (que je n'ai pas utilisé depuis longtemps) a quelque chose appelé categories pour étendre les classes. Déclarant une catégorie avec de nouvelles méthodes et la compilant dans votre programme, toutes les instances de la classe ont soudainement les nouvelles méthodes.Comment faire Catégories Obj-C en Python?

Python a des possibilités de mixage, que j'utilise, mais les mixins doivent être utilisés depuis le bas du programme: la classe doit le déclarer lui-même. Use-case Catégorie de cas d'utilisation: Supposons que vous ayez une grande hiérarchie de classes qui décrivent différentes manières d'interagir avec des données, en déclarant des méthodes polymorphiques pour obtenir différents attributs. Maintenant, une catégorie peut aider le consommateur de ces classes décrivant en mettant en œuvre une interface pratique pour accéder à ces méthodes en un seul endroit. (Une méthode de catégorie pourrait, par exemple, essayer deux méthodes différentes et renvoyer la première valeur de retour définie (non-None).)

Une façon de faire cela en Python?

Code illustrative

Je espoir cela clarifie ce que je veux dire. Le point est que la catégorie est comme une interface agrégée, que le consommateur d'AppObj peut changer son code.

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

Dans votre exemple, seriez-vous instancier AppObj ou AppObjCategory? BTW Python a des décorateurs de classe maintenant dans 2.6: http://docs.python.org/whatsnew/2.6.html#pep-3129-class-decorators –

+0

J'instancie AppObj (et ses sous-classes). Le code de catégorie peut être complètement séparé (par exemple AppObj peut être dans une bibliothèque, la catégorie dans l'application). – u0b34a0f6ae

+0

Peut-être que c'est juste un cas pour implémenter le décorateur de catégorie Catégorie à ce moment-là; copier tous les attributs de la catégorie vers la classe de base, en ignorant certains attributs comme .. __doc__ et __dict__? – u0b34a0f6ae

Répondre

2

J'utilise python2.5 donc je ne l'ai pas testé avec la syntaxe du décorateur (ce qui serait bien), et je ne suis pas sûr que ce soit vraiment correct. Mais il ressemble à ceci:

pycategories.py

""" 
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

Pourquoi ne pas simplement ajouter des méthodes dynamiquement?

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

Je connais Objective-C et cela ressemble à des catégories. Le seul inconvénient est que vous ne pouvez pas faire cela pour les types intégrés ou d'extension. Je suis venu avec cette implémentation d'un décorateur de la classe

+1

seule différence est que la catégorie est plus systématique ou explicite, surtout si vous connaissez déjà le concept. – u0b34a0f6ae

+0

Je voudrais juste ajouter ce petit peu d'aide connexe: vous pouvez obtenir les superclasses d'un objet en utilisant '__class __.__ mro__' sur cet objet. Cela peut être utile si vous avez plusieurs classes auxquelles vous souhaitez ajouter la méthode et recherchez leur superclasse commune. – ArtOfWarfare

2

fonction Python setattr rend facile.

# 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 
Questions connexes