str metodo ejemplo def __str__ __init__ python class variables object instance

ejemplo - metodo__str__ python



Obtener un nombre de instancia dentro de la clase__init__() (10)

Esta pregunta ya tiene una respuesta aquí:

Mientras construyo un nuevo objeto de clase en python, quiero poder crear un valor predeterminado basado en el nombre de instancia de la clase sin pasar un argumento adicional. ¿Cómo puedo lograr esto? Aquí está el pseudo-código básico que estoy intentando:

class SomeObject(): defined_name = u"" def __init__(self, def_name=None): if def_name == None: def_name = u"%s" % (<INSTANCE NAME>) self.defined_name = def_name ThisObject = SomeObject() print ThisObject.defined_name # Should print "ThisObject"


Bueno, hay casi una manera de hacerlo:

#!/usr/bin/env python import traceback class SomeObject(): def __init__(self, def_name=None): if def_name == None: (filename,line_number,function_name,text)=traceback.extract_stack()[-2] def_name = text[:text.find(''='')].strip() self.defined_name = def_name ThisObject = SomeObject() print ThisObject.defined_name # ThisObject

El módulo de rastreo le permite mirar el código utilizado para llamar a SomeObject (). Con una pequeña secuencia de cadenas, text[:text.find(''='')].strip() puedes adivinar cuál debería ser el def_name.

Sin embargo, este truco es frágil. Por ejemplo, esto no funciona tan bien:

ThisObject,ThatObject = SomeObject(),SomeObject() print ThisObject.defined_name # ThisObject,ThatObject print ThatObject.defined_name # ThisObject,ThatObject

Por lo tanto, si tuviera que usar este truco, debe tener en cuenta que debe llamar a SomeObject () usando una simple declaración de Python:

ThisObject = SomeObject()

Por cierto, como otro ejemplo de uso de rastreo, si define

def pv(var): # stack is a list of 4-tuples: (filename, line number, function name, text) # see http://docs.python.org/library/traceback.html#module-traceback # (filename,line_number,function_name,text)=traceback.extract_stack()[-2] # (''x_traceback.py'', 18, ''f'', ''print_var(y)'') print(''%s: %s''%(text[text.find(''('')+1:-1],var))

entonces puedes llamar

x=3.14 pv(x) # x: 3.14

para imprimir tanto el nombre de la variable como su valor.


Creo que los nombres son importantes si son los indicadores de cualquier objeto. No importa si:

foo = 1 bar = foo

Sé que foo señala a 1 y la barra apunta al mismo valor 1 en el mismo espacio de memoria. pero supongamos que quiero crear una clase con una función que le agregue un objeto.

Class Bag(object): def __init__(self): some code here... def addItem(self,item): self.__dict__[somewaytogetItemName] = item

Entonces, cuando hago una instancia de la clase de bolsa como a continuación:

newObj1 = Bag() newObj2 = Bag() newObj1.addItem(newObj2)I can do this to get an attribute of newObj1: newObj1.newObj2


En Python, todos los datos se almacenan en objetos. Además, un nombre se puede vincular con un objeto, después de lo cual ese nombre se puede utilizar para buscar ese objeto.

No importa al objeto a qué nombres, si los hay, podría estar vinculado. Puede estar vinculado a docenas de nombres diferentes, o ninguno. Además, Python no tiene ningún "vínculo de retroceso" que apunte desde un objeto a un nombre.

Considera este ejemplo:

foo = 1 bar = foo baz = foo

Ahora, suponga que tiene el objeto entero con el valor 1, y desea trabajar hacia atrás y encontrar su nombre. ¿Qué imprimirías? Tres nombres diferentes tienen ese objeto vinculado a ellos, y todos son igualmente válidos.

print(bar is foo) # prints True print(baz is foo) # prints True

En Python, un nombre es una forma de acceder a un objeto, por lo que no hay forma de trabajar con nombres directamente. Puede buscar en varios espacios de nombres hasta que encuentre un nombre que esté vinculado con el objeto de interés, pero no lo recomiendo.

¿Cómo obtengo la representación de cadena de una variable en python?

Hay una famosa presentación llamada "Code Like a Pythonista" que resume esta situación como "Otros idiomas tienen ''variables''" y "Python tiene ''nombres''"

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables


Esto no puede funcionar, solo imagine esto: a = b = TheMagicObjet() . Los nombres no tienen efecto en los valores, solo apuntan a ellos.


Inspirado por las respuestas de unutbu y Saullo Castro, he creado una clase más sofisticada que incluso puede ser subclasificada. Resuelve lo que se pidió en la pregunta.

"cree un valor predeterminado basado en el nombre de instancia de la clase sin pasar un argumento extra".

Esto es lo que hace, cuando se crea una instancia de esta clase o una subclase:

  1. Suba en la pila de cuadros hasta el primer cuadro que no pertenece a un método de la instancia actual.
  2. Inspeccione este marco para obtener los atributos self.creation_(name/file/module/function/line/text) .
  3. Realice una verificación adicional de si un objeto con nombre self.creation_name se definió realmente en el espacio de nombres locals () del marco para asegurarse al 100% de que el nombre de creación encontrado sea correcto o genere un error de lo contrario.

El código:

import traceback, threading, time class InstanceCreationError(Exception): pass class RememberInstanceCreationInfo: def __init__(self): for frame, line in traceback.walk_stack(None): varnames = frame.f_code.co_varnames if varnames is (): break if frame.f_locals[varnames[0]] not in (self, self.__class__): break # if the frame is inside a method of this instance, # the first argument usually contains either the instance or # its class # we want to find the first frame, where this is not the case else: raise InstanceCreationError("No suitable outer frame found.") self._outer_frame = frame self.creation_module = frame.f_globals["__name__"] self.creation_file, self.creation_line, self.creation_function, / self.creation_text = / traceback.extract_stack(frame, 1)[0] self.creation_name = self.creation_text.split("=")[0].strip() super().__init__() threading.Thread(target=self._check_existence_after_creation).start() def _check_existence_after_creation(self): while self._outer_frame.f_lineno == self.creation_line: time.sleep(0.01) # this is executed as soon as the line number changes # now we can be sure the instance was actually created error = InstanceCreationError( "/nCreation name not found in creation frame./ncreation_file: " "%s /ncreation_line: %s /ncreation_text: %s/ncreation_name (" "might be wrong): %s" % ( self.creation_file, self.creation_line, self.creation_text, self.creation_name)) nameparts = self.creation_name.split(".") try: var = self._outer_frame.f_locals[nameparts[0]] except KeyError: raise error finally: del self._outer_frame # make sure we have no permament inter frame reference # which could hinder garbage collection try: for name in nameparts[1:]: var = getattr(var, name) except AttributeError: raise error if var is not self: raise error def __repr__(self): return super().__repr__()[ :-1] + " with creation_name ''%s''>" % self.creation_name

Un ejemplo simple:

class MySubclass(RememberInstanceCreationInfo): def __init__(self): super().__init__() def print_creation_info(self): print(self.creation_name, self.creation_module, self.creation_function, self.creation_line, self.creation_text, sep=", ") instance = MySubclass() #out: instance, __main__, <module>, 68, instance = MySubclass()

Si el nombre de la creación no se puede determinar correctamente, se genera un error:

variable, another_instance = 2, MySubclass() # InstanceCreationError: # Creation name not found in creation frame. # creation_file: /.../myfile.py # creation_line: 71 # creation_text: variable, another_instance = 2, MySubclass() # creation_name (might be wrong): variable, another_instance


La mejor manera es realmente pasar el nombre al constructor como en la respuesta elegida. Sin embargo, si REALMENTE desea evitar pedirle al usuario que le pase el nombre al constructor, puede hacer lo siguiente:

Si está creando la instancia con ''ThisObject = SomeObject ()'' desde la línea de comandos, puede obtener el nombre del objeto de la cadena de comandos en el historial de comandos:

import readline import re class SomeObject(): def __init__(self): cmd = readline.get_history_item(readline.get_current_history_length()) self.name = re.split(''=| '',cmd)[0]

Si está creando la instancia con el comando ''exec'', puede manejar esto con:

if cmd[0:4] == ''exec'': self.name = re.split(''/'|=| '',cmd)[1] # if command performed using ''exec'' else: self.name = re.split(''=| '',cmd)[0]


Las instancias no tienen nombre. En el momento en que el nombre global ThisObject se enlaza a la instancia creada al evaluar el constructor SomeObject , el constructor ha terminado de ejecutarse.

Si desea que un objeto tenga un nombre, simplemente pase el nombre en el constructor.

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


Puede crear un método dentro de su clase que verifique todas las variables en el marco actual y use hash() para buscar la variable self .

La solución propuesta aquí devolverá todas las variables que apuntan al objeto de instancia.

En la clase a continuación, isinstance() se usa para evitar problemas al aplicar hash() , ya que algunos objetos como un numpy.array o una list , por ejemplo, no se pueden lavar.

import inspect class A(object): def get_my_name(self): ans = [] frame = inspect.currentframe().f_back tmp = dict(frame.f_globals.items() + frame.f_locals.items()) for k, var in tmp.items(): if isinstance(var, self.__class__): if hash(self) == hash(var): ans.append(k) return ans

Se ha realizado la siguiente prueba:

def test(): a = A() b = a c = b print c.get_my_name()

El resultado es:

test() #[''a'', ''c'', ''b'']


Si desea un nombre de instancia único para una clase, intente __repr__() o id(self)

class Some: def __init__(self): print(self.__repr__()) # = hex(id(self)) print(id(self))

Imprimirá la dirección de memoria de la instancia, que es única.


Una manera horrible, horrible de lograr esto es revertir las responsabilidades:

class SomeObject(): def __init__(self, def_name): self.defined_name = def_name globals()[def_name] = self SomeObject("ThisObject") print ThisObject.defined_name

Si quisieras apoyar algo que no fuera el alcance global, tendrías que hacer algo aún más horrible.