2012-07-01 3 views
4

Say есть:Python методы динамического класса

class A(B): 
    ... 

где B может быть object и ... является не:

@classmethod # or @staticmethod 
def c(cls): print 'Hello from c!' 

Что я должен сделать, что вызов A.c() обыкновение триггер AttributeError?

Другими словами, я знаю, что можно вручную добавить методы класса в класс во время выполнения. Но возможно ли это сделать автоматически, скажем, каждый раз, когда отсутствует метод класса, он создает какой-то фиктивный метод?

В еще Другие слова, только если я мог бы заменить A.__dict__ с моим Словарем, который обрабатывает __getitem__ - но A.__dict__, кажется, не доступен для записи ...

ответ

11

Вы можете добиться этого с помощью __getattr__ hook на metaclass.

class DefaultClassMethods(type): 
    def __getattr__(cls, attr): 
     def _defaultClassMethod(cls): 
      print 'Hi, I am the default class method!' 
     setattr(cls, attr, classmethod(_defaultClassMethod)) 
     return getattr(cls, attr) 

Демо:

>>> class DefaultClassMethods(type): 
...  def __getattr__(cls, attr): 
...   def _defaultClassMethod(cls): 
...    print 'Hi, I am the default class method!' 
...   setattr(cls, attr, classmethod(_defaultClassMethod)) 
...   return getattr(cls, attr) 
... 
>>> class A(object): 
...  __metaclass__ = DefaultClassMethods 
... 
>>> A.spam 
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>> 
>>> A.spam() 
Hi, I am the default class method! 

Обратите внимание, что мы устанавливаем результат classmethod вызова прямо на класс, эффективно кэшировать его для будущих поисков.

Если вам необходимо регенерировать метод класса при каждом вызове вместо этого, использовать те же method to bind a function to an instance, но с классом и метаклассом вместо (с использованием cls.__metaclass__, чтобы соответствовать метаклассу подклассы):

from types import MethodType 

class DefaultClassMethods(type): 
    def __getattr__(cls, attr): 
     def _defaultClassMethod(cls): 
      print 'Hi, I am the default class method!' 
     return _defaultClassMethod.__get__(cls, cls.__metaclass__) 

Для статических методов просто вернуть функцию непосредственно во всех случаях, не нужно гадать с декоратором staticmethod или протоколом дескриптора.

+0

A.asd() - AttributeError: «Тип объекта 'А' no attribute 'asd' " –

+0

@EcirHana: ах, вы имеете в виду метод класса по умолчанию, будет обновляться. –

+0

Я хочу, чтобы спам был методом класса, а не методом экземпляра. –

0
>>> class C(object): 
...  pass 
... 
>>> C.m = classmethod(lambda cls: cls.__name__) 
>>> C.m() 
'C' 

Или вы можете использовать somethigs, как это:

class Wrapper(object): 

    def __init__(self, clz, default=lambda cls: None): 
     self._clz = clz 
     self._default = default 

    def __getattr__(self, attr): 
     # __attrs__ will be getted from Wrapper 
     if attr.startswith('__'): 
      return self.__getattribute__(attr) 

     if not hasattr(self._clz, attr): 
      setattr(self._clz, attr, classmethod(self._default)) 
     return getattr(self._clz, attr) 

    def __call__(self, *args, **kwargs): 
     return self._clz(*args, **kwargs) 

>>> class C(object): 
...  pass 
... 
>>> C = Wrapper(C, default=lambda cls: cls.__name__) 
>>> c = C() 
>>> print C.m() 
'C' 
>>> print c.m() # now instance have method "m" 
'C' 
+0

Спасибо. Да, я знаю, что вы можете добавлять методы класса вручную. Есть ли способ сделать это автоматически? –

+0

@EcirHana, python создает объекты класса при импорте модулей. И этот класс-объект не имеет метода '__getattribute__' или некоторого эквивалента ... – astynax

+0

@ EcirHana, я попытался реализовать какую-то оболочку ... – astynax

1

поведений, предоставляемые экземпляры методами, как __getattr__ и протокол дескриптора может работать для классов, а также, но в этом случае, вы должны закодируйте их в метаклассе класса.

В этом случае все, что нужно сделать, это установить функцию метакласса __getattr__ для автоматического создания требуемого атрибута класса.

(The SetAttr, GetAttr Хитрость заключается в том, чтобы сделать Python FUNCTION-> метод transoform без необходимости возиться с ним)

class AutoClassMethod(type): 
    def __getattr__(cls, attr): 
     default = classmethod(lambda cls: "Default class method for " + repr(cls)) 
     setattr(cls, attr, default) 
     return getattr(cls, attr) 



class A(object): 
    __metaclass__ = AutoClassMethod 
    @classmethod 
    def b(cls): 
     print cls 
Смежные вопросы