Re: Type annotation pitfall
On Fri, Sep 24, 2021 at 11:43 PM Peter Saalbrink wrote: > > I don't think this has anything to do with typing or providing type hints. > The type hint is the `: set` part, not the `= set()` part. > You can declare the type without assigning to the variable. > Indeed, as you already said, `x` is a class property here, and is shared > amongst instances of the class. > It might be a good idea to move the attribute assignment to the `__init__` > method. > > In the following way, you can safely provide the type hint: > > ```python > class Foo: > x: set > > def __init__(self, s): > self.x = set() > if s: > self.x.add(s) > ``` > To be clear, this isn't a case of "never use mutables as class attributes"; often you *want* a single mutable object to be shared among instances of a class (so they can all find each other, perhaps). If you want each instance to have its own set, you construct a new set every object initialization; if you want them to all use the same set, you construct a single set and attach it to the class. Neither is wrong, they just have different meanings. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Type annotation pitfall
On 24/09/21 5:48 pm, Robert Latest wrote: Never use mutable types in type hint, No, the lesson is: Don't mutate a shared object if you don't want the changes to be shared. If you want each instance to have its own set object, you need to create one for it in the __init__ method, e.g. class Foo(): x : set def __init__(self, s): self.x = set() if s: self.x.add(s) -- Greg -- https://mail.python.org/mailman/listinfo/python-list
Re: Type annotation pitfall
I don't think this has anything to do with typing or providing type hints. The type hint is the `: set` part, not the `= set()` part. You can declare the type without assigning to the variable. Indeed, as you already said, `x` is a class property here, and is shared amongst instances of the class. It might be a good idea to move the attribute assignment to the `__init__` method. In the following way, you can safely provide the type hint: ```python class Foo: x: set def __init__(self, s): self.x = set() if s: self.x.add(s) ``` Or, even shorter: ```python class Foo: def __init__(self, s: str): self.x: set[str] = {s} if s else set() print(reveal_type(Foo.x)) # mypy only ``` On Fri, Sep 24, 2021 at 7:58 AM Robert Latest via Python-list < python-list@python.org> wrote: > Hi all, > > this just caused me several hours of my life until I could whittle it down > to > this minimal example. Simple question: Why is the x member of object "foo" > modified by initializing "bar"? > > Obviously, initializing foo with None doesn't set foo.x at all. So I guess > x > stays a class property, not an instance property. And instantiating bar > just > added an item to the class property but didn't instantiate a new set. So > basically, neither foo nor bar ever had their "own" x, right? > > Oooohh, dangerous! Never use mutable types in type hint, unless it's in > explicit dataclasses (which automatically add an appropriate __init__()?) > > Now I must fine-comb all my code for more of these. > > class Foo(): > x : set = set() > > def __init__(self, s): > if s: > self.x.add(s) > > foo = Foo(None) > print(foo.x) # prints 'set()' > bar = Foo('abc') > print(foo.x) # prints '{'abc'} > > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list
Type annotation pitfall
Hi all, this just caused me several hours of my life until I could whittle it down to this minimal example. Simple question: Why is the x member of object "foo" modified by initializing "bar"? Obviously, initializing foo with None doesn't set foo.x at all. So I guess x stays a class property, not an instance property. And instantiating bar just added an item to the class property but didn't instantiate a new set. So basically, neither foo nor bar ever had their "own" x, right? Oooohh, dangerous! Never use mutable types in type hint, unless it's in explicit dataclasses (which automatically add an appropriate __init__()?) Now I must fine-comb all my code for more of these. class Foo(): x : set = set() def __init__(self, s): if s: self.x.add(s) foo = Foo(None) print(foo.x) # prints 'set()' bar = Foo('abc') print(foo.x) # prints '{'abc'} -- https://mail.python.org/mailman/listinfo/python-list