@@ -661,6 +661,41 @@ Usually, users would use these attributes in combinations with
661
661
in SOURCE format, one could write
662
662
``annotationlib.call_evaluate_function(T.evaluate_bound, annotationlib.Format.SOURCE) ``.
663
663
664
+ Behavior of dataclass field types
665
+ =================================
666
+
667
+ One consequence of the deferred evaluation of annotations is that
668
+ dataclasses can use forward references in their annotations:
669
+
670
+ .. code :: pycon
671
+
672
+ >>> from dataclasses import dataclass
673
+ >>> @dataclass
674
+ ... class D:
675
+ ... x: undefined
676
+ ...
677
+
678
+ However, the ``FORWARDREF `` format leaks into the field types of the dataclass:
679
+
680
+ .. code :: pycon
681
+
682
+ >>> fields(D)[0].type
683
+ ForwardRef('undefined')
684
+
685
+ We considered a change where the ``.type `` attribute of a field object would
686
+ trigger evaluation of annotations, so that the field type could contain actual
687
+ values in the case of forward references that were defined after the dataclass
688
+ itself was created, but before the field type is accessed.
689
+ However, this would also mean that accessing ``.type `` could now run arbitrary
690
+ code in the annotation, and potentially throws errors such as :py:exc: `NameError `.
691
+
692
+ Therefore, we consider it more user-friendly to keep the ``ForwardRef `` object
693
+ in the type, and document that users who want to resolve forward references
694
+ can use the ``ForwardRef.evaluate `` method.
695
+
696
+ If use cases come up in the future, we could add additional functionality,
697
+ such as a new method that re-evaluates the annotation from scratch.
698
+
664
699
Miscellaneous implementation details
665
700
====================================
666
701
@@ -793,63 +828,6 @@ as we make progress on implementing it. Readers are encouraged to follow the
793
828
implementation of the PEP and try out the draft implementation. Any feedback may
794
829
be incorporated into future versions of this PEP.
795
830
796
- Should dataclass field types use deferred evaluation?
797
- -----------------------------------------------------
798
-
799
- The current draft implementation already supports deferred evaluation in dataclasses,
800
- so this works:
801
-
802
- .. code :: pycon
803
-
804
- >>> from dataclasses import dataclass
805
- >>> @dataclass
806
- ... class D:
807
- ... x: undefined
808
- ...
809
-
810
- However, the ``FORWARDREF `` format leaks into the field types of the dataclass:
811
-
812
- .. code :: pycon
813
-
814
- >>> fields(D)[0].type
815
- ForwardRef('undefined')
816
-
817
- We could instead add deferred evaluation for the field type, similar to that outlined
818
- above for type alias values.
819
-
820
- Accessing ``.type `` might throw an error:
821
-
822
- .. code :: pycon
823
-
824
- >>> @dataclass
825
- ... class D:
826
- ... x: undefined
827
- ...
828
- >>> field = fields(D)[0]
829
- >>> field.type
830
- Traceback (most recent call last):
831
- File "<python-input-4>", line 1, in <module>
832
- field.type
833
- File ".../dataclasses.py", line 308, in type
834
- annos = self._annotate(annotationlib.Format.VALUE)
835
- File "<python-input-2>", line 3, in __annotate__
836
- x: undefined
837
- ^^^^^^^^^
838
- NameError: name 'undefined' is not defined
839
-
840
- But users could use ``annotationlib.call_evaluate_function `` to get the type in other formats:
841
-
842
- .. code :: pycon
843
-
844
- >>> annotationlib.call_evaluate_function(field.evaluate_type, annotationlib.Format.SOURCE)
845
- 'undefined'
846
- >>> annotationlib.call_evaluate_function(field.evaluate_type, annotationlib.Format.FORWARDREF)
847
- ForwardRef('undefined')
848
-
849
- Other variations are possible. For example, we could leave the ``type `` attribute unchanged,
850
- and only add the ``evaluate_type `` method. This avoids unpleasant surprises where accessing
851
- ``.type `` may throw an exception.
852
-
853
831
Acknowledgments
854
832
===============
855
833
0 commit comments