Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

210
Visualizações
¿Por qué la excepción de Python realiza un seguimiento de los objetos pasados a __init__?

Por favor, consulte el siguiente fragmento de código:

 In [1]: class A(Exception): ...: def __init__(self, b): ...: self.message = b.message ...: In [2]: class B: ...: message = "hello" ...: In [3]: A(B()) Out[3]: __main__.A(<__main__.B at 0x14af96790>) In [4]: class A: ...: def __init__(self, b): ...: self.message = b.message ...: In [5]: A(B()) Out[5]: <__main__.A at 0x10445b0a0>

si A subclase de Exception , su repr devuelve una referencia a B() aunque solo pasemos el atributo de mensaje de B() .

¿Por qué es este el comportamiento intencional en Exception.repr y cómo funciona en python psuedocode si es posible dado que el código cpython no es demasiado legible?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Muy bien, creo que he encontrado el truco. Aquí está el código fuente de C, pero volveré a implementar algo similar en Python para demostrarlo.

Además del __init__ habitual (que está anulando), Python también tiene un método mágico llamado __new__ . Cuando construyes una A como A(B()) , está haciendo algo más o menos como

 b = B() a = A.__new__(A, b) a.__init__(b)

Ahora, ha anulado A.__init__ , por lo que Exception.__init__ nunca se llama. Pero A.__new__ es simplemente Exception.__new__ (más precisamente, es BaseException.__new__ , que es esencialmente el código fuente C que vinculé). Y, según el código vinculado, eso es aproximadamente

 class BaseException: def __new__(cls, *args): obj = object.__new__(cls) obj.args = args return obj

Entonces almacenamos explícitamente la tupla de argumentos en un campo llamado args en el objeto de excepción. Esta es la tupla de argumentos reales pasada al constructor, incluso si __init__ . Entonces, repr solo hace referencia a self.args para recuperar los argumentos originales.

Tenga en cuenta que estoy siendo un poco impreciso aquí. Si BaseException.__new__ en REPL, verá que todavía es object.__new__ . Las devoluciones de llamada de C funcionan de manera diferente y usan algo de magia de compilación a la que no tenemos acceso, pero la idea básica es la misma.

over 4 years ago · Santiago Trujillo Relatório

0

Cuando se crea un objeto de Python, se llama al método __new__ de la clase, y luego se llama a __init__ en la nueva instancia que devuelve el método __new__ (suponiendo que devuelva una nueva instancia, que a veces no lo hace).

Su método __init__ anulado no mantiene una referencia a b , pero no __new__ , por lo que hereda el método __new__ definido aquí ( enlace fuente de CPython ):

 static PyObject * BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { // ... if (args) { self->args = args; Py_INCREF(args); return (PyObject *)self; } // ... }

Omití las partes que no son relevantes. Como puede ver, el método __new__ de la clase BaseException almacena una referencia a la tupla de argumentos utilizados al crear la excepción y, por lo tanto, esta tupla está disponible para que el método __repr__ imprima una referencia a los objetos utilizados para instanciar la excepción. Entonces es esta tupla la que retiene una referencia al argumento original b . Esto es consistente con la expectativa general de que repr debería devolver el código de Python que crearía un objeto en el mismo estado, si es posible.

Tenga en cuenta que solo args , no kwds , tiene este comportamiento; el método __new__ no almacena una referencia a kwds y __repr__ no la imprime, por lo que deberíamos esperar no ver el mismo comportamiento si se llama al constructor con un argumento de palabra clave en lugar de un argumento posicional. Efectivamente, eso es lo que observamos:

 >>> A(B()) A(<__main__.B object at 0x7fa8e7a23860>,) >>> A(b=B()) A()

Un poco extraño ya que se supone que los dos objetos A tienen el mismo estado, pero así es como se escribe el código, de todos modos.

over 4 years ago · Santiago Trujillo Relatório

0

Podemos explorar la diferencia con la pestaña de Ipython completa.

 In [230]: a=A(B()) In [231]: a Out[231]: __main__.A(<__main__.B at 0x7f29cd1e71c0>)

Con la pestaña de ipython completa:

 In [234]: a. args a.bin message a.npy with_traceback() a.t1 In [234]: a.args Out[234]: (<__main__.B at 0x7f29cd1e71c0>,)

La clase sin excepción, solo tiene un atributo, message :

 In [235]: a1=A1(B()) In [236]: a1 Out[236]: <__main__.A1 at 0x7f29ccc21a60> In [237]: a1.message Out[237]: 'hello'

y una simple excepción:

 In [238]: e=Exception(B()) In [239]: e Out[239]: Exception(<__main__.B at 0x7f29ccd0e790>) In [240]: e. args with_traceback()

Y usando a como excepción:

 In [240]: raise(a) Traceback (most recent call last): File "<ipython-input-240-cf5e5bb7d43e>", line 1, in <module> raise(a) A: <__main__.B object at 0x7f29cd1e71c0>
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda