Quando tento usar um método estático de dentro do corpo da classe e defino o método estático usando a staticmethod
função interna como decorador, desta forma:
class Klass(object):
@staticmethod # use as decorator
def _stat_func():
return 42
_ANS = _stat_func() # call the staticmethod
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
Estou tendo o erro a seguir:
Traceback (most recent call last):<br>
File "call_staticmethod.py", line 1, in <module>
class Klass(object):
File "call_staticmethod.py", line 7, in Klass
_ANS = _stat_func()
TypeError: 'staticmethod' object is not callable
Entendo por que isso está acontecendo (ligação do descritor) e posso contornar isso convertendo-o manualmente _stat_func()
em um método estático após seu último uso, da seguinte forma:
class Klass(object):
def _stat_func():
return 42
_ANS = _stat_func() # use the non-staticmethod version
_stat_func = staticmethod(_stat_func) # convert function to a static method
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
Então, minha pergunta é:
Existem melhores, como em formas mais limpas ou mais "pitônicas", para conseguir isso?
python
decorator
static-methods
Martineau
fonte
fonte
staticmethod
. Eles geralmente são mais úteis como funções no nível do módulo; nesse caso, seu problema não é um problema.classmethod
, Por outro lado ...Respostas:
staticmethod
os objetos aparentemente têm um__func__
atributo que armazena a função bruta original (faz sentido que eles precisassem). Então, isso vai funcionar:Além disso, embora eu suspeitasse que um objeto staticmethod tivesse algum tipo de atributo armazenando a função original, eu não tinha ideia dos detalhes. No espírito de ensinar alguém a pescar em vez de dar a ele um peixe, foi o que eu fiz para investigar e descobrir isso (um C&P da minha sessão em Python):
Tipos semelhantes de escavação em uma sessão interativa (
dir
é muito útil) geralmente podem resolver esses tipos de perguntas muito rapidamente.fonte
__func__
é apenas outro nomeim_func
e foi adicionado ao Py 2.6 para compatibilidade com versões anteriores do Python 3.__func__
atributo de um método estático fornece uma referência à função original, exatamente como se você nunca tivesse usado ostaticmethod
decorador. Portanto, se sua função exigir argumentos, você precisará passá-los ao chamar__func__
. A mensagem de erro de que você parece parece que não deu argumentos. Se ostat_func
exemplo deste post tivesse dois argumentos, você usaria_ANS = stat_func.__func__(arg1, arg2)
stat_func
ela mesma é uma variável). Você quis dizer que não pode usar atributos de instância da classe que está definindo? Isso é verdade, mas não surpreende; não temos uma instância da classe, pois ainda estamos definindo a classe! Mas, de qualquer maneira, eu apenas as pretendia como suporte para quaisquer argumentos que você desejasse passar; você poderia usar literais lá.É assim que eu prefiro:
Prefiro esta solução a
Klass.stat_func
, por causa do princípio DRY . Lembra-me da razão pela qual há um novosuper()
no Python 3 :)Mas eu concordo com os outros, geralmente a melhor opção é definir uma função no nível do módulo.
Por exemplo, com a
@staticmethod
função, a recursão pode não parecer muito boa (você precisaria quebrar o princípio DRY ligando paraKlass.stat_func
dentroKlass.stat_func
). Isso ocorre porque você não tem referência aoself
método estático interno. Com a função no nível do módulo, tudo ficará bem.fonte
self.__class__.stat_func()
métodos regulares tenha vantagens (DRY e tudo isso) sobre o usoKlass.stat_func()
, esse não foi realmente o tópico da minha pergunta - na verdade, evitei usá-lo para não obscurecer a questão da inconsistência.self.__class__
é melhor porque se uma subclasse substituirstat_func
,Subclass.method
ela chamará a subclassestat_func
. Mas, para ser completamente honesto, nessa situação, é muito melhor usar apenas um método real em vez de estático.Que tal injetar o atributo de classe após a definição da classe?
fonte
Isso ocorre porque o staticmethod é um descritor e requer uma busca de atributo no nível da classe para exercitar o protocolo do descritor e obter a verdadeira capacidade de chamada.
Do código fonte:
Mas não diretamente de dentro da classe enquanto ela está sendo definida.
Mas como um comentarista mencionou, esse não é realmente um design "pitonico". Basta usar uma função de nível de módulo.
fonte
E essa solução? Não depende do conhecimento da
@staticmethod
implementação do decorador. Classe interna StaticMethod é reproduzida como um contêiner de funções de inicialização estática.fonte
__func__
lo, porque agora está oficialmente documentado (consulte a seção Outras alterações de idioma do que há de novo no Python 2.7 e sua referência ao problema 5982 ). Sua solução é ainda mais portátil, pois provavelmente também funcionaria nas versões Python anteriores ao 2.6 (quando__func__
foi introduzido pela primeira vez como sinônimo deim_func
).