python: cómo referirse a la clase desde dentro (como la función recursiva)

Para una función recursiva podemos hacer:

def f(i): if i<0: return print i f(i-1) f(10) 

Sin embargo, ¿hay una manera de hacer lo siguiente?

 class A: # do something some_func(A) # ... 

En Python no puedes hacer referencia a la clase en el cuerpo de la clase, aunque en lenguajes como Ruby puedes hacerlo.

En Python, en cambio, puedes usar un decorador de clase, pero se llamará una vez que la clase se haya inicializado. Otra forma podría ser usar metaclase, pero depende de lo que estés tratando de lograr.

No puede con la syntax específica que describe debido al momento en que se evalúan. La razón por la que funciona la función de ejemplo dada es que la llamada a f (i-1) dentro del cuerpo de la función se debe a que la resolución del nombre de f no se realiza hasta que la función se llama realmente. En este punto f existe dentro del scope de la ejecución ya que la función ya ha sido evaluada. En el caso del ejemplo de clase, la referencia al nombre de la clase se busca mientras la definición de la clase aún se está evaluando. Como tal, aún no existe en el ámbito local.

Alternativamente, el comportamiento deseado se puede lograr usando una metaclase como:

 class MetaA(type): def __init__(cls): some_func(cls) class A(object): __metaclass__=MetaA # do something # ... 

Usando este enfoque, puede realizar operaciones arbitrarias en el objeto de clase en el momento en que se evalúa la clase.

Si quieres referirte al mismo objeto, solo usa ‘self’:

 class A: def some_func(self): another_func(self) 

Si desea crear un nuevo objeto de la misma clase, simplemente hágalo:

 class A: def some_func(self): foo = A() 

Si desea tener acceso al objeto de la clase de metaclase (lo más probable es que no sea lo que quiere), de nuevo, simplemente hágalo:

 class A: def some_func(self): another_func(A) # note that it reads A, not A() 

No Funciona en una función porque los contenidos de la función se ejecutan en el momento de la llamada. Pero los contenidos de la clase se ejecutan en el momento de la definición, momento en el que la clase aún no existe.

Normalmente no es un problema porque puede hackear a más miembros en la clase después de definirlos, por lo que puede dividir una definición de clase en varias partes:

 class A(object): spam= 1 some_func(A) A.eggs= 2 def _A_scramble(self): self.spam=self.eggs= 0 A.scramble= _A_scramble 

Sin embargo, es bastante inusual querer llamar a una función en la clase en medio de su propia definición. No está claro qué intentas hacer, pero es probable que estés mejor con los decoradores (o los decoradores de clase relativamente nuevos).

No hay una manera de hacerlo dentro del scope de la clase, no a menos que A se haya definido para que sea otra cosa primero (y luego some_func (A) hará algo completamente diferente de lo que usted espera)

A menos que esté haciendo algún tipo de inspección de stack para agregar bits a la clase, parece extraño por qué querría hacer eso. ¿Por qué no solo?

 class A: # do something pass some_func(A) 

Es decir, ejecute some_func en A después de que se haya realizado. Alternativamente, puedes usar un decorador de clase (syntax para esto fue agregado en 2.6) o metaclase si quisieras modificar la clase A de alguna manera. ¿Podrías aclarar tu caso de uso?

Si quieres hacer un poco de piratería, hazlo.

 class A(object): ... some_func(A) 

Si quieres hacer algo más sofisticado puedes usar una metaclase. Una metaclase es responsable de manipular el objeto de clase antes de que se cree completamente. Una plantilla sería:

 class AType(type): def __new__(meta, name, bases, dct): cls = super(AType, meta).__new__(meta, name, bases, dct) some_func(cls) return cls class A(object): __metaclass__ = AType ... 

type es la metaclase por defecto Las instancias de metaclases son clases, por lo que __new__ devuelve una instancia modificada de (en este caso) A

Para obtener más información sobre las metaclases, consulte http://docs.python.org/reference/datamodel.html#customizing-class-creation .

¿Qué quieres lograr? Es posible acceder a una clase para modificar su definición utilizando una metaclase, pero no se recomienda.

Su ejemplo de código se puede escribir simplemente como:

 class A(object): pass some_func(A) 

Está bien hacer referencia al nombre de la clase dentro de su cuerpo (como dentro de las definiciones de métodos) si está realmente dentro del scope … Lo que será si se define en el nivel superior. (En otros casos, probablemente no, debido a las peculiaridades del scope de Python).

Para una ilustración del scope del bash, intente crear una instancia de Foo:

 class Foo(object): class Bar(object): def __init__(self): self.baz = Bar.baz baz = 15 def __init__(self): self.bar = Foo.Bar() 

(Se quejará de que no se haya definido el nombre global ‘Barra’).


Además, algo me dice que es posible que desee consultar los métodos de clase: los documentos sobre la función de método de clase (para usarlos como decorador), una pregunta SO relevante . Edit: Ok, entonces esta sugerencia puede no ser apropiada en absoluto … Es solo que lo primero en lo que pensé al leer tu pregunta fue en cosas como constructores alternativos, etc. Si algo más simple se adapta a tus necesidades, @classmethod rareza de @classmethod . 🙂

Si el objective es llamar a una función some_func con la clase como argumento, una respuesta es declarar some_func como decorador de clase. Tenga en cuenta que se llama al decorador de clase después de que se inicializa la clase. Se pasará la clase que está siendo decorada como argumento.

 def some_func(cls): # Do something print(f"The answer is {cls.x}") return cls # Don't forget to return the class @some_func class A: x = 1 

Si desea pasar argumentos adicionales a some_func , debe devolver una función del decorador:

 def some_other_func(prefix, suffix): def inner(cls): print(f"{prefix} {cls.__name__} {suffix}") return cls return inner @some_other_func("Hello", " and goodbye!") class B: x = 2 

Los decoradores de clase se pueden componer, lo que hace que se llamen en el orden inverso al que se declaran:

 @some_func @some_other_func("Hello", "and goodbye!") class C: x = 42 

El resultado de lo cual es:

 # Hello C and goodbye! # The answer is 42 

La mayoría del código en la clase estará dentro de las definiciones de los métodos, en cuyo caso simplemente puede usar el nombre A