2009-08-20 10 views
9

Obj-C (które nie były używane przez dłuższy czas) ma coś, co nazywa categories przedłużyć klas. Deklarując kategorię nowymi metodami i kompilując ją do swojego programu, wszystkie instancje klasy nagle mają nowe metody.Jak zrobić kategorie Obj-C w Pythonie?

wstawek Python ma możliwości, których używam, ale wstawek należy stosować od dołu programu: klasa musi to zadeklarować się.

Przypadek użycia przypadku: Powiedz, że masz dużą hierarchię klas opisującą różne sposoby interakcji z danymi, deklarującą polimorficzne sposoby uzyskiwania różnych atrybutów. Teraz kategoria może pomóc konsumentowi w opisywaniu klas poprzez wdrożenie wygodnego interfejsu umożliwiającego dostęp do tych metod w jednym miejscu. (Sposób kategoria może na przykład spróbować dwóch różnych metod i zwróci pierwszy zdefiniowana (non-None) wartości zwracanej.)

jakikolwiek sposób zrobić to w Pythonie?

kod poglÄ

I nadzieja ten wyjaśnia, co mam na myśli. Chodzi o to, że kategoria jest jak kruszywa interfejsem, że konsument AppObj można zmienić w kodem.

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

W przykładzie byś instancję AppObj lub AppObjCategory? BTW Python ma teraz dekoratory klas w wersji 2.6: http://docs.python.org/whatsnew/2.6.html#pep-3129-class-decorators –

+0

Tworzę instancję AppObj (i jej podklasy). Kod kategorii może być całkowicie oddzielny (tzn. AppObj może znajdować się w bibliotece, kategoria w aplikacji). – u0b34a0f6ae

+0

Może to tylko przypadek za wdrażanie Kategoria klasy dekoratora tuż potem; skopiować wszystkie atrybuty od kategorii, do klasy bazowej, pomijając pewne atrybuty jak .. __doc__ i __dict__? – u0b34a0f6ae

Odpowiedz

2

Wpadłem na tę implementację dekoratora klas. Używam Pythona2.5, więc nie przetestowałem go z użyciem składni dekoratora (co byłoby miłe) i nie jestem pewien, co robi jest naprawdę poprawne. Ale wygląda to tak:

pycategories.py setattr funkcja

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

Dlaczego po prostu nie dodawać metod w sposób dynamiczny?

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

Znam Objective-C i to wygląda jak kategorie. Jedyną wadą jest to, że nie można tego zrobić w przypadku typów wbudowanych lub rozszerzeń.

+1

Jedyną różnicą jest to, że kategoria jest bardziej systematyczna lub wyraźna, szczególnie jeśli znasz już tę koncepcję. – u0b34a0f6ae

+0

Chciałbym tylko dodać tę niewielką część pokrewnej pomocy: można uzyskać nadklasy obiektu, używając '__class __.__ mro__' na tym obiekcie. Może to być użyteczne, jeśli masz wiele klas, do których chcesz dodać metodę i szukasz wspólnej superklasy. – ArtOfWarfare

2

Pythona czyni to łatwe.

# 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