2011-05-05 6 views
10

Могу ли я определить метод Python как статический, так и экземпляр одновременно? Что-то вроде:Статические методы и экземпляры в Python

class C(object): 
    @staticmethod 
    def a(self, arg1): 
     if self: 
      blah 
     blah 

Так что я могу назвать его как:

C.a(arg1) 
C().a(arg1) 

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

+2

Вы попробовали? –

+0

http://stackoverflow.com/questions/5812537/can-i-have-a-method-of-a-class-which-can-be-used-as-a-staticmethod-or-instance-me определенно интересно. Мне просто интересно, есть ли способ «взломать» это – xster

ответ

17
import functools 

class static_or_instance(object): 
    def __init__(self, func): 
    self.func = func 

    def __get__(self, instance, owner): 
    return functools.partial(self.func, instance) 

class C(object): 
    @static_or_instance 
    def a(self, arg): 
    if self is None: 
     print "called without self:", arg 
    else: 
     print "called with self:", arg 

C.a(42) 
C().a(3) 
+4

Очень круто. Но я ненавижу: D –

+0

Вы сделали это. Я не могу поверить, что ты это сделал! – jathanism

+0

очень круто. – Haranadh

2

№ Что будет self означает внутри метода, если бы вы могли это сделать?

1

Ваш код будет работать, если вы удалите параметр self до a(). Когда вы вызываете его с помощью C().a(arg1), экземпляр игнорируется.

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

+0

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

+1

Вам лучше перейти на переменные, которые вы хотите использовать из метода. Тогда вам все равно, являются ли они переменными экземпляра или нет. – jathanism

4

formencode имеет декоратор classinstancemethod, который делает то, что вы хотите. Для этого требуется метод, чтобы иметь 2 аргумента (self и cls, один из них может получить переданные None в зависимости от вызывающего контекста)

поднятого с formencode/declarative.py

class classinstancemethod(object): 
    """ 
    Acts like a class method when called from a class, like an 
    instance method when called by an instance. The method should 
    take two arguments, 'self' and 'cls'; one of these will be None 
    depending on how the method was called. 
    """ 

    def __init__(self, func): 
     self.func = func 

    def __get__(self, obj, type=None): 
     return _methodwrapper(self.func, obj=obj, type=type) 

class _methodwrapper(object): 

    def __init__(self, func, obj, type): 
     self.func = func 
     self.obj = obj 
     self.type = type 

    def __call__(self, *args, **kw): 
     assert not kw.has_key('self') and not kw.has_key('cls'), (
      "You cannot use 'self' or 'cls' arguments to a " 
      "classinstancemethod") 
     return self.func(*((self.obj, self.type) + args), **kw) 

    def __repr__(self): 
     if self.obj is None: 
      return ('<bound class method %s.%s>' 
        % (self.type.__name__, self.func.func_name)) 
     else: 
      return ('<bound method %s.%s of %r>' 
        % (self.type.__name__, self.func.func_name, self.obj)) 

Пример использования

class A(object): 
    data = 5 

    @classinstancemethod 
    def print_(self=None, cls=None): 
     ctx = self or cls 
     print ctx.data 


>>> A.print_() 
5 
>>> a = A() 
>>> a.data = 4 
>>> a.print_() 
4 
Смежные вопросы