Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Suggestion: Consider changing the order for variable initialization in `__init__`

Aperta
#1,296 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
python
Ambito
tooling

Direzione di ricerca

Start by reading the documentation section describing default factories and the generated init behavior. Then trace how attrs generates initialization for fields with supplied values, defaults, and factories, and check whether tests cover factory ordering or the NOTHING sentinel. Done means the proposed ordering is evaluated with tests and the supported behavior is documented or declined.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Feature

First of all thanks a lot for the awesome library! I just recently discovered it and it saved me so many headaches. Recently I was trying to do something of this sort, where either x or y has to be given to the __init__ method for this to be valid:

@define
class MyClass:
    x: int = field()
    y: int = field()
    
    @x.default
    def y_plus_one(self):
        return self.y + 1
        
    @y.default
    def x_plus_one(self):
        return self.x + 1

This however (as the docs state) fails because self.y would not be initialized during the call to y_plus_one. Even though the docs state this fails I wanted to try and fix the issue and managed to do so in a very hacky way. However in the process I thought up a non invasive way in which this may work.

If we first initialize those fields that were given a value through __init__ and then use the NOTHING sentinel to initialize the values for those attributes that were not initialized through __init__ but before calling the factories, the problem dissapears. The reordered __init__ method would look something like this (I'm not really sure how the method is autogenerated but its a rough idea):

@define
class MyClass:
    ...
    
    def __init__(self, x = NOTHING, y = NOTHING): # <- this is autogenerated
        # initialize all fields before calling factories
        if x is not NOTHING:
            self.x = x
        elif isinstance(self.__attrs_attrs__['x'].default, Factory):
            self.x = NOTHING
        elif self.__attrs_attrs__['x'].default is not None:
            self.x = self.__attrs_attrs__['x'].default

        if y is not NOTHING:
            self.y = y
        elif isinstance(self.__attrs_attrs__['y'].default, Factory):
            self.y = NOTHING
        elif self.__attrs_attrs__['y'].default is not None:
            self.y = self.__attrs_attrs__['y'].default

        # call the factories for all fields that were not given a value through init
        if self.x is NOTHING and isinstance(self.__attrs_attrs__['x'].default, Factory):
            self.x = self.__attrs_attrs__['x'].default.factory(self)
            if self.x is NOTHING:
                raise ValueError("a factory may not return the NOTHING sentinel")

        if self.y is NOTHING and isinstance(self.__attrs_attrs__['y'].default, Factory):
            self.y = self.__attrs_attrs__['y'].default.factory(self)
            if self.y is NOTHING:
                raise ValueError("a factory may not return the NOTHING sentinel")
    
    ...

This has the additional benefit that now I can throw more descriptive error messages during initialization, like:

    ...
    @x.default
    def y_plus_one(self):
        if self.y is NOTHING:
            raise ValueError("either x or y has to be initialized")
        return self.y + 1
    ...
Lingua principale
Python
Stelle
5.8k
Fork
480
Merge medio
2h 15m
PR unite (30g)
2

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di python-attrs/attrs

Tutte le issue di python-attrs/attrs

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.