otra - programacion orientada a objetos python pdf
Cómo crear un nuevo objeto desconocido o dinámico/expando en Python (5)
Si adopta el enfoque de metaclases de la respuesta de @Martijn, la respuesta de @Ned se puede volver a escribir más corta (aunque obviamente es menos legible, pero hace lo mismo).
obj = type(''Expando'', (object,), {})()
obj.foo = 71
obj.bar = ''World''
O simplemente, que hace lo mismo que arriba usando el argumento dict
:
obj = type(''Expando'', (object,), {''foo'': 71, ''bar'': ''World''})()
Para Python 3, no es necesario pasar el objeto al argumento de bases
(consulte la documentación de type
).
Pero para casos simples, la creación de instancias no tiene ningún beneficio, por lo que está bien:
ns = type(''Expando'', (object,), {''foo'': 71, ''bar'': ''World''})
Al mismo tiempo, personalmente prefiero una clase simple (es decir, sin creación de instancias) para los casos de configuración de prueba ad-hoc como más simple y legible:
class ns:
foo = 71
bar = ''World''
Actualizar
En Python 3.3+ hay exactamente lo que pide OP, types.SimpleNamespace
. Es solo
Una subclase de
object
simple que proporciona acceso de atributo a su espacio de nombres, así como una reproducción significativa.A diferencia del
object
, conSimpleNamespace
puedes agregar y eliminar atributos. Si un objetoSimpleNamespace
se inicializa con argumentos de palabras clave, se agregan directamente al espacio de nombres subyacente.
import types
obj = types.SimpleNamespace()
obj.a = 123
print(obj.a) # 123
print(repr(obj)) # namespace(a=123)
Sin embargo, en stdlib de Python 2 y Python 3 hay argparse.Namespace
, que tiene el mismo propósito:
Objeto simple para almacenar atributos.
Implementa la igualdad por nombres de atributos y valores, y proporciona una representación de cadena simple.
import argparse
obj = argparse.Namespace()
obj.a = 123
print(obj.a) # 123
print(repr(obj)) # Namespace(a=123)
Tenga en cuenta que ambos pueden inicializarse con argumentos de palabras clave:
types.SimpleNamespace(a = ''foo'',b = 123)
argparse.Namespace(a = ''foo'',b = 123)
En Python, ¿cómo podemos crear un nuevo objeto sin tener una clase predefinida y luego agregarle propiedades dinámicamente?
ejemplo:
dynamic_object = Dynamic()
dynamic_object.dynamic_property_a = "abc"
dynamic_object.dynamic_property_b = "abcdefg"
¿Cuál es la mejor manera de hacerlo?
EDITAR Debido a que muchas personas comentaron en los comentarios que no podría necesitar esto.
La cosa es que tengo una función que serializa las propiedades de un objeto. Por esa razón, no quiero crear un objeto de la clase esperada debido a algunas restricciones de los constructores, sino crear uno similar, digamos como un simulacro , agregar las propiedades "personalizadas" que necesito, luego enviarlas a la función.
Solo define tu propia clase para hacerlo:
class Expando(object):
pass
ex = Expando()
ex.foo = 17
ex.bar = "Hello"
Una forma que encontré es también creando un lambda. Puede tener efectos secundarios y viene con algunas propiedades que no se desean. Sólo publicar para el interés.
dynamic_object = lambda:expando
dynamic_object.dynamic_property_a = "abc"
dynamic_object.dynamic_property_b = "abcdefg"
Usar un objeto solo para mantener valores no es el estilo de programación más Pythonic. Es común en los lenguajes de programación que no tienen buenos contenedores asociativos, pero en Python, puedes usar un diccionario:
my_dict = {} # empty dict instance
my_dict["foo"] = "bar"
my_dict["num"] = 42
También puede usar un "diccionario literal" para definir todos los contenidos del diccionario a la vez:
my_dict = {"foo":"bar", "num":42}
O, si sus claves son todas identificadoras legales (y lo serán, si planeaba que fueran nombres de atributos), puede usar el constructor dict
con argumentos de palabras clave como pares clave-valor:
my_dict = dict(foo="bar", num=42) # note, no quotation marks needed around keys
De hecho, completar un diccionario es lo que Python está haciendo entre bambalinas cuando usas un objeto, como en la respuesta de Ned Batchelder. Los atributos de su ex
objeto se almacenan en un diccionario, ex.__dict__
, que debería terminar siendo igual a un dict
equivalente creado directamente.
A menos que la sintaxis de atributos (por ejemplo, ex.foo
) sea absolutamente necesaria, también puede omitir el objeto por completo y usar un diccionario directamente.
Use la fábrica de clases collections.namedtuple()
para crear una clase personalizada para su valor de retorno:
from collections import namedtuple
return namedtuple(''Expando'', (''dynamic_property_a'', ''dynamic_property_b''))(''abc'', ''abcdefg'')
El valor devuelto se puede utilizar tanto como tupla como por acceso de atributo:
print retval[0] # prints ''abc''
print retval.dynamic_property_b # prints ''abcdefg''