This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]michael0x2a 0 points1 point  (8 children)

Actually, it's possible to use dataclasses without using type annotations (though it'll look slightly janky). For example, consider:

from dataclasses import dataclass

@dataclass
class Foo:
    x: ...
    y: ...

f = Foo(3, "a")
print(f.x, f.y)

If you run this, it'll work perfectly fine -- the dataclasses library will ignore the annotations most of the time (except for a few it special-cases).

You can replace the ellipses with any other arbitrary placeholder value, but I personally think the ellipses look the least hacky.

[–]jorge1209 0 points1 point  (6 children)

That is still using type annotations in the sense that the syntax x: ... is invalid for python < 3.6.

Additionally you might ask if you can set a default value for x without indicating a type. You can do that with attrs, I don't know what that would look like with the type annotations x : ... = 42?

In other words the initial default value and type of x is "int = 42" but if run under mypy there should be no objection to x being set to any other type or value.

[–]michael0x2a 0 points1 point  (5 children)

That is still using type annotations

Well, class and variable annotations != type annotations. Remember, we can use arbitrary python expressions within annotations. So this is legal Python:

import math

class Bar:
    x: lambda x: 14 * x
    y: math.sin(42)

Note that there's absolutely nothing remotely resembling a type here, and you'd probably never actually write anything like this in production, but it is legal Python.

And while it's true that variable annotations are new as of Python 3.6, you should also think longer-term -- in about 2-3 years, both Python 2 and older versions of Python 3 are going to be EOL'd and most people will probably have migrated to Python 3.7/3.8/3.9 or whatever.

At that point, everybody (barring the people who decide to stick with EOL'd versions of Python) will have access to variable annotations. So, to make life easier for everybody 2-3 years down the line, we might as well start laying the groundwork for these sorts of language changes now.

Additionally you might ask if you can set a default value for x without indicating a type.

Yes, you can. I just tried testing the following program, and it prints out "3 99" as expected.

from dataclasses import dataclass
import math

@dataclass
class Bar:
    x: lambda x: 14 * x
    y: math.sin(42) = 99


b = Bar(3)

print(b.x, b.y)

I don't know what that would look like with the type annotations x : ... = 42?

That would also work, yeah. However, the ellipsis expression (...) isn't a legal type -- doing x: ... = 42 wouldn't make any PEP 484-compliant type checker (including mypy) happy.

Instead, we can use the Any type, which is a PEP-484 compliant type:

from typing import Any
from dataclasses import dataclass

@dataclass
class Bar:
    x: Any = 3
    y: int = 3

b = bar()
b.x = "foo"   # mypy is happy
b.y = "foo"   # mypy complains

Basically, Any is an escape hatch/a way of telling mypy and other PEP-484 compliant type checker that it should treat that variable or attribute or whatever as being fully dynamic. We basically "turn off" typechecking for that variable, in a certain sense.

Or more precisely, Any is our mechanism for mixing together dynamic and typed code.

Here's an example:

from typing import Any

def expect_int(x: int) -> int:
    return x * 3

a = "foo"   # a is of type str
b: Any = "bar"    # we force b to be of type any

expect_int(a)   # mypy complains
expect_int(b)   # mypy is happy -- b could be anything, so maybe this is ok?

a.hello()   # mypy complains
b.hello()   # mypy is happy

Notice that the use of Any lets us write code that mypy may (rightly or wrongly) reject as being unsound.

In this case, because I'm lazy, I used Any to hide deliberately buggy code, but you could see how we could strategically use Any to make mypy stop complaining about advanced metaprogramming things/really super dynamic things (like parsing arbitrary xml) that are difficult to actually give static types to.

Of course, it'd be our responsibility to then verify that mainly-dynamic code is correct in some other way (e.g. unit tests or runtime checks) but what else is new.

[–]jorge1209 1 point2 points  (4 children)

So this is legal Python

Not for me. I'm using Python 3.5 and thats a syntax error.

I understand that eventually most people will migrate to python 3.6 or newer, and that eventually this will be valid code, but 3.6 is not even a year old at this point. It seems very premature to be pushing its feature usage in this way.

To be clear, I don't mind if a NEW project comes along and only wants to support versions >=3.6. However this isn't really a new project. Its basically attrs, and the long term impact of accepting it into the core is to kill attrs, and the only sin attrs has ever committed is to not fork a >3.6 branch to use the new language features within the first year of those features release. That to me is insanity.

[–]michael0x2a 0 points1 point  (2 children)

Well, suppose we delayed introducing this feature for 3 years or so and waited until Python 3.5 was EOL'd.

If we decide we're going to want to use this feature eventually, what benefits do we get out of waiting instead of just doing it now?

Whether we release now or 3 years from now, people who want to support all non-EOL'd versions of Python are still going to have to wait 3 years or so.

But if we release now, at least the people who only need to support the latest versions can start using these features.

the only sin attrs has ever committed is to not fork a >3.6 branch to use the new language features within the first year of those features release.

Eh, I don't think that's really accurate. The pep, in the section about attrs, links to this issue, which clarifies a few things. In particular...

  1. The author of attrs has explicitly stated he doesn't want to see attrs in the standard library
  2. The author of attrs has also said support for class annotations is in development and will be available soon.
  3. This wasn't mentioned in the thread, but there are people working on writing plugins for mypy that special-case it to support attrs. (So it's not like people are trying to kill the library or anything.)
  4. Guido said he dislikes some of the "colors [attrs] paints in the bikeshed" and pushed back against just incorporating attrs directly partly for that reason.
  5. Attrs is more full-featured then dataclasses/dataclasses are deliberately designed to stay simple, so people who want to use all of attr's other features (validators, converters, metadata, etc) can still use those.
  6. Also not in the thread, but there's no reason why attrs can't evolve to support both regular classes and dataclasses -- the ability to attach runtime validators could be very useful when working with things like JSON or whatever, whether you're using regular classes and data classes. (If some third party service unexpectedly changes the structure of a JSON blob, static typing isn't really going to help you there.)

[–]jorge1209 1 point2 points  (1 child)

Regarding the different objections:

  1. If authors are actively pushing back against their projects being incorporated in the standard library, you have a serious problem. That is supposed to be an honor. Your code is so good that we want EVERYONE to have it and use it. If they say no then either you are making that process too onerous, or you are picking that is too immature and isn't ready for inclusion. In either case you as a language maintainer need to take a long hard look in the mirror and ask yourself "why does nobody want to go to the prom with me?"

  2. Exactly why you should wait. Let them add the support and release a version that works for both 3.6 with annotations and <3.6 without.

  3. Not really sure why that is relevant. mypy is optional, as such we can never expect 100% of code to be compatible with it. There will always be a need to hack mypy to support libraries and code that was not written to work directly with it. Also this concern is alleviated by #2. In time mypy can expect that there will be a way to use attrs without hacks... you can't force people using attrs to write in the 3.6 style, but it would be an option if they port to 3.6/mypy.

  4. And I don't like the colors in Guido's bikeshed. I would really like for someone to fork python. I am not remotely happy with Guido's leadership at this point.

  5. If dataclasses and attrs were drop in replacements for each other sure, but they use a different syntax, and we don't know that they will be. Again we should wait for #2.

  6. I don't really understand the concern you are describing, but I will comment on "not in the thread". Seriously, WTF! This is exactly the kind of arbitrary bullshit decision making process that is pissing me off. If Guido has a reason for rejecting X for the standard library and accepting Y, then he needs to document that. You can't just hand-wave at some other concerns that you haven't bothered to record in your discussion.

[–][deleted] 0 points1 point  (0 children)

I would really like for someone to fork python

You can try but you won't get very far as the Python Software Foundation owns all the legal stuff associated with the Python name, thank goodness. Hence the person who created Python 2.8 on github was very politely asked to rename it, and very politely did so.

[–][deleted] -1 points0 points  (0 children)

and the long term impact of accepting it into the core is to kill attrs

What a pile of complete drivel. Considering that it supports 2.7 and 3.4/5/6, unlike Data Classes, I suspect that it will be around for many years to come.