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

508
Visualizações
¿Cómo puedo obtener el nombre del atributo cuando trabajo con el protocolo descriptor en Python?

El protocolo del descriptor funciona bien, pero todavía tengo un problema que me gustaría resolver.

Tengo un descriptor:

 class Field(object): def __init__(self, type_, name, value=None, required=False): self.type = type_ self.name = "_" + name self.required = required self._value = value def __get__(self, instance, owner): return getattr(instance, self.name, self.value) def __set__(self, instance, value): if value: self._check(value) setattr(instance, self.name, value) else: setattr(instance, self.name, None) def __delete__(self, instance): raise AttributeError("Can't delete attribute") @property def value(self): return self._value @value.setter def value(self, value): self._value = value if value else self.type() @property def _types(self): raise NotImplementedError def _check(self, value): if not isinstance(value, tuple(self._types)): raise TypeError("This is bad")

Esto se subclasifica:

 class CharField(Field): def __init__(self, name, value=None, min_length=0, max_length=0, strip=False): super(CharField, self).__init__(unicode, name, value=value) self.min_length = min_length self.max_length = max_length self.strip = strip @property def _types(self): return [unicode, str] def __set__(self, instance, value): if self.strip: value = value.strip() super(CharField, self).__set__(instance, value)

Y luego se usa una clase modelo:

 class Country(BaseModel): name = CharField("name") country_code_2 = CharField("country_code_2", min_length=2, max_length=2) country_code_3 = CharField("country_code_3", min_length=3, max_length=3) def __init__(self, name, country_code_2, country_code_3): self.name = name self.country_code_2 = country_code_2 self.country_code_3 = country_code_3

Hasta ahora, todo bien, esto funciona tal como se esperaba.

El único problema que tengo aquí es que tenemos que dar un nombre de campo cada vez que se declara un campo. por ejemplo "country_code_2" para el campo country_code_2 .

¿Cómo sería posible obtener el nombre del atributo de la clase modelo y usarlo en la clase de campo?

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

0

Hay una manera simple, y hay una manera difícil.

La forma simple es usar Python 3.6 (o más reciente) y darle a su descriptor un método object.__set_name__() adicional:

 def __set_name__(self, owner, name): self.name = '_' + name

Cuando se crea una clase, Python llamará automáticamente a ese método en cualquier descriptor que establezca en la clase, pasando el objeto de la clase y el nombre del atributo.

Para versiones anteriores de Python, la mejor opción siguiente es usar una metaclase ; se llamará para cada subclase que se cree, y se le otorgará un nombre de atributo de asignación de diccionario útil para el valor del atributo (incluidas las instancias de su descriptor). A continuación, puede aprovechar esta oportunidad para pasar ese nombre al descriptor:

 class BaseModelMeta(type): def __new__(mcls, name, bases, attrs): cls = super(BaseModelMeta, mcls).__new__(mcls, name, bases, attrs) for attr, obj in attrs.items(): if isinstance(obj, Field): obj.__set_name__(cls, attr) return cls

Esto llama al mismo __set_name__() en el campo, que Python 3.6 admite de forma nativa. Luego use eso como la metaclase para BaseModel :

 class BaseModel(object, metaclass=BaseModelMeta): # Python 3

o

 class BaseModel(object): __metaclass__ = BaseModelMeta # Python 2

También puede usar un decorador de clase para hacer las llamadas __set_name__ para cualquier clase con la que lo decore, pero eso requiere que decore cada clase. En su lugar, una metaclase se propaga automáticamente a través de la jerarquía de herencia.

over 4 years ago · Santiago Trujillo Relatório

0

Analizo esto en mi libro, Descriptores de Python , aunque no he actualizado a una segunda edición para agregar la nueva función en 3.6. Aparte de eso, es una guía bastante completa sobre descriptores, con 60 páginas sobre una sola característica.

De todos modos, una forma de obtener el nombre sin metaclases es con esta función muy simple:

 def name_of(descriptor, instance): attributes = set() for cls in type(instance).__mro__: # add all attributes from the class into `attributes` # you can remove the if statement in the comprehension if you don't want to filter out attributes whose names start with '__' attributes |= {attr for attr in dir(cls) if not attr.startswith('__')} for attr in attributes: if type(instance).__dict__[attr] is descriptor: return attr

Teniendo en cuenta que cada vez que usa el nombre del descriptor, la instancia está involucrada, esto no debería ser demasiado difícil de descubrir cómo usarlo. También puede encontrar una manera de almacenar en caché el nombre una vez que lo haya buscado por primera vez.

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