ericvsmith / dataclasses

Apache License 2.0
587 stars 53 forks source link

Skipping fields in the constructor signature #15

Closed gvanrossum closed 7 years ago

gvanrossum commented 7 years ago

I often have instance variables that are not part of the constructor arguments. The current design doesn't seem to let me specify their types using the nice x: int notation, since that implies they are included in the constructor signature. E.g. (almost from asyncio):

class Server:
    def __init__(self, loop, sockets):
        self._loop = loop
        self.sockets = sockets
        self._active_count = 0
        self._waiters = []

I'd like to add types, like such:

@dataclass
class Server:
    loop: AbstractEventLoop
    sockets: List[socket.socket]
    _activecount: int = 0
    _waiters: List[Future] = []  # or field(factory=list)

But I'd need to have a way to say "these fields should not be part of the constructor".

ericvsmith commented 7 years ago

You can say

@dataclass
class Server:
    loop: AbstractEventLoop
    _activecount: int = field(default=0, init=False)

Some of the generated code will look like:

def __init__(_self,i:_type_i):
    _self.i=i
def __repr__(_self)->_type__return:
    return _self.__class__.__name__ + f"(_activecount={_self._activecount!r},i={_self.i!r})"

So the field is excluded from __init__. (The __repr__ could could be smarter, I'll fix that.)

>>> s = Server(None)
>>> s
Server(loop=None,_activecount=0)

There are similar flags for omitting from repr, comparison functions, hash, etc.

Does this do what you need?

ilevkivskyi commented 7 years ago

It is already possible to do this with this syntax see tests:

@whatever
class Server:
    loop: AbstractEventLoop
    sockets: List[socket.socket]
    _activecount: int = field(init=False, default=0)
    _waiters: List[Future] = field(init=False, factory=list)
gvanrossum commented 7 years ago

OK, that's good enough for me.