Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Most elegant way to avoid None objects in class? #400

Closed
madig opened this issue Jun 22, 2018 · 3 comments
Closed

Most elegant way to avoid None objects in class? #400

madig opened this issue Jun 22, 2018 · 3 comments
Labels

Comments

@madig
Copy link

@madig madig commented Jun 22, 2018

(continuing from #170 which I don't want to derail)

I have a class like this:

@attr.s(frozen=True, auto_attribs=True)
class Status:
    weight: int = attr.ib(cmp=True)
    message: str = attr.ib(
        cmp=False,
        converter=lambda value: str() if value is None else value,
    )
    code: str = attr.ib(
        cmp=False,
        converter=lambda value: str() if value is None else value,
    )

    @classmethod
    def Debug(cls, message=None, code=None):
        return cls(weight=0, message=message, code=code)

    [...]

    @classmethod
    def Error(cls, message=None, code=None):
        return cls(weight=6, message=message, code=code)

It can be instantiated like this: Status.Error("This and that is wrong etc.", code="mismatched-something"). However, instantiating it like Status.Error() should result in Status(weight=6, message="", code=""), i.e. I want to avoid None objects. Python unfortunately makes it more tedious than it should be to give out non-None default arguments.

@hynek noted that I may want to use default="" and use attr.NOTHING as the default argument in the constructors, however:

In [1]: import attr
   ...: @attr.s
   ...: class Status:
   ...:     a = attr.ib(default="")
   ...:     @classmethod
   ...:     def aaa(cls, a=attr.NOTHING):
   ...:         return cls(a)
   ...:

In [2]: Status.aaa()
Out[2]: Status(a=NOTHING)

In [3]: Status.aaa("")
Out[3]: Status(a='')

In [4]: import attr
   ...: @attr.s
   ...: class Status:
   ...:     a = attr.ib(default="")
   ...:     @classmethod
   ...:     def aaa(cls, a=None):
   ...:         return cls(a=a or attr.NOTHING)

In [5]: Status.aaa()
Out[5]: Status(a=NOTHING)
@madig
Copy link
Author

@madig madig commented Jun 22, 2018

(I suppose I can use def aaa(cls, a=""): here because strings are immutable, but I'd like to know about a more general approach.)

Loading

@hynek
Copy link
Member

@hynek hynek commented Jun 22, 2018

Ugh right the NOTHING way doesn’t work because attrs uses literal "" as default parameters if possible.

Loading

@hynek
Copy link
Member

@hynek hynek commented Jun 22, 2018

I guess what could be done is some kind of attr.converters.default_if_none(default=NOTHING, factory=None) so you could write attr.converters.default_if_none(default="") or attr.converters.default_if_none(factory=list). I think I had uses for that too before. 🤔

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants