Pergunta

Say estou declarando um C classe e algumas das declarações são muito semelhantes. Eu gostaria de usar uma função f para reduzir repetição de código para estas declarações. É possível apenas declarar e usar f como de costume:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

Ops! Eu inadvertidamente expostos f para o mundo exterior, mas não é preciso ser um argumento self (e não pode por razões óbvias). Uma possibilidade seria a de del a função depois que eu usá-lo:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

Mas e se eu quiser usar f novamente mais tarde, após a declaração? Não vai fazer para apagar a função. Eu poderia fazê-lo "private" (ou seja, prefixo seu nome com __) e dar-lhe o tratamento @staticmethod, mas invocando objetos staticmethod através de canais anormais fica muito funk:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

Eu tenho que usar a loucura acima porque os objetos staticmethod, que são descritores, não são eles próprios que pode ser chamado. Eu preciso para recuperar a função envolto pelo objeto staticmethod antes que eu possa chamá-lo.

Não tem que ser uma maneira melhor de fazer isso. Como posso limpa declarar uma função em uma classe, usá-lo durante a sua declaração, e também usá-lo depois de dentro da classe? Devo mesmo estar fazendo isso?

Foi útil?

Solução

Muito simplesmente, a solução é que f não precisa ser um membro da classe. Estou assumindo que o seu processo de pensamento passou por um filtro de idioma Javaish causando o bloqueio mental. Ele vai um pouco algo como isto:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

Então, quando você quiser usar f novamente, apenas usá-lo

>>> f(4)
'<4>'

Eu acho que a moral do conto é "Em Python, você não Have à força tudo em uma classe".

Outras dicas

Ali A resposta 's, se você realmente quer evitar f no espaço de nomes do módulo (e usando um nome não exportado como _f, ou configuração __all__ não é suficiente), então você poderia conseguir isso criando a classe dentro de um fechamento.

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

Desta forma C tem acesso a f dentro de sua definição e métodos, mas nada mais faz (com exceção de introspecção bastante envolvidos de seus métodos (C.method_using_f.im_func.func_closure))

Este é provavelmente um exagero para a maioria dos propósitos embora - documentando que f é interno usando o "_" convenção de prefixo nameing deve geralmente ser suficiente.

[Edit] Uma outra opção é manter uma referência ao objeto de função pré-embalados nos métodos que você deseja usá-lo em Por exemplo, definindo-o como um argumento padrão:.

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(Embora eu acho que a abordagem de encerramento é provavelmente melhor)

Esta é uma possibilidade:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

Eu acredito que você está tentando fazer isso:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

Talvez não há melhor ou mais Python solução ...

"declarar uma função em uma classe, usá-lo durante a sua declaração, e também usá-lo depois de dentro da classe"

Sorry. não pode ser feito.

"Não pode ser feito" não parece se dar bem com Python

Uma opção: escrever uma staticmethod melhor:

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

Vamos começar desde o início.

"declarar uma função em uma classe, usá-lo durante a sua declaração, e também usá-lo depois de dentro da classe"

Sorry. não pode ser feito. "Em uma classe" contradiz "usados ??durante a declaração".

  • Em um meio classe criada como parte da declaração.
  • Usado durante meio de declaração ela existe fora da classe. Muitas vezes, como uma classe meta. No entanto, existem outras maneiras.

Não está claro o que C.w e C.v é suposto ser. eles são apenas cordas? Se assim for, um f função externa é a melhor solução. O "não atravancar a namespace" é um pouco enganoso. Afinal, você quer usá-lo novamente.

É no mesmo módulo como C. É por isso que Python tem módulos. Ele se liga a função e classe juntos.

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

Se w e V não são cadeias simples, há uma solução muito boa que dá muita flexibilidade.

Geralmente, para a classe de nível ( "estático") variáveis ??como esta, podemos usar outras classes. Não é possível alcançar completamente a API desejado, mas isso é perto.

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

A vantagem disto é que F é uma coisa adequada, de primeira classe que pode ser estendido. Não é uma coisa "escondida" que nós estamos tentando evitar a exposição. É um fato da vida, de modo que poderia muito bem seguir o / princípio de fechamento Abrir e torná-lo abrir a extensão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top