Python Forum
Function Annotation got NameError: name 'xxx' is not defined
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Function Annotation got NameError: name 'xxx' is not defined
#1
I am introducing function annotation in my coding, but found both python and Pycharm will validate if the type in function annotation is valid, if a none defined type is used, it will raise error. It's different with the statement in PEP 3107: "By itself, Python does not attach any particular meaning or significance to annotations. " (https://www.python.org/dev/peps/pep-3107...nnotations). This will be very boring in case of some circular reference situation, eg. below coding will get warning hint from Pycharm and get error when running:
class Cls1:
    def __init__(self):
        self.sibling:Cls2 = None

    def setSibling(self, cls: Cls2):
        self.sibling = cls


class Cls2:
    def __init__(self):
        self.sibling: Cls1 = None

    def setSibling(self, cls: Cls1):
        self.sibling = cls
Traceback (most recent call last):
File "Module1.py", line 1, in <module>
class Cls1:
File "Module1.py", line 5, in Cls1
def setSibling(self, cls: Cls2):
NameError: name 'Cls2' is not defined



Alternatively, I have to use python 2 style type remarks as below, and it works.
class Cls1:
    def __init__(self):
        self.sibling:Cls2 = None

    def setSibling(self, cls):
        # type: (Cls2)
        self.sibling = cls


class Cls2:
    def __init__(self):
        self.sibling: Cls1 = None

    def setSibling(self, cls):
        #type: (Cls1)
        self.sibling = cls
Same with normal coding logic, the type hint inside a function allows type defined afterward but the type in function annotation must be defined in advance, but in circular reference situation, it's almost impossible. Does python 3 function annotation isn't fully complied with PEP 3107 statement or there is other thing which I don't know?
Reply
#2
PEP 3107 Wrote:All annotation expressions are evaluated when the function definition is executed, just like default values.

This all seems consistent with PEP 3107. Annotations are expressions which are evaluated. In order to evaluate anything in Python, all the names must be defined. This precludes circular annotations like you are trying to do.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#3
(Oct-22-2019, 02:08 PM)ichabod801 Wrote:
PEP 3107 Wrote:All annotation expressions are evaluated when the function definition is executed, just like default values.
This all seems consistent with PEP 3107. Annotations are expressions which are evaluated. In order to evaluate anything in Python, all the names must be defined. This precludes circular annotations like you are trying to do.


Thanks for your advice, but this type of circular reference is valid requirement, right? eg. two type of classes with parent and child relation. In other static languages, with type definition in advance, there is no any problem. On another hand, In above case that I showed, python allows circular reference inside function and it works without function annotation, but it's not allowed in function annotation, which will limit the usage of function annotation, do you have any solution except python 2 style type remarks which I used now?
Reply
#4
You can do the circular references within a function because the code within the function is not executed until you call the function. At that point the relevant names have been defined.

I don't think you can get around this. The only thing I can think of is to define a dummy version of Cls2, then Cls1 with the Cls2 annotation, then Cls2 with the Cls1 annotation. But with the way names work in Python, I expect that the annotation in Cls1 will still point to the evaluated dummy Cls2.

Another idea is to have Cls1 and Cls2 both inherit from Cls0, and use Cls0 as the annotation. Not as precise as you want, but it's something.

Doing some more research, it appears PEP 583 calls for delayed evaluation of annotations. This was implemented in 3.7 and can be imported from __future__ as annotations. Otherwise PEP 484 recommends using a string of the expression, which should be evaluated once the module is fully loaded.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#5
(Oct-23-2019, 01:39 AM)ichabod801 Wrote: You can do the circular references within a function because the code within the function is not executed until you call the function. At that point the relevant names have been defined. I don't think you can get around this. The only thing I can think of is to define a dummy version of Cls2, then Cls1 with the Cls2 annotation, then Cls2 with the Cls1 annotation. But with the way names work in Python, I expect that the annotation in Cls1 will still point to the evaluated dummy Cls2. Another idea is to have Cls1 and Cls2 both inherit from Cls0, and use Cls0 as the annotation. Not as precise as you want, but it's something. Doing some more research, it appears PEP 583 calls for delayed evaluation of annotations. This was implemented in 3.7 and can be imported from __future__ as annotations. Otherwise PEP 484 recommends using a string of the expression, which should be evaluated once the module is fully loaded.

I tried dummy Cls2 solution, that could 'cheat' python interpreter but Pycharm still refers Cls2 to the dummy one, so it could not help for IDE typing hint which is biggest value for me now. Cls0 solution has same issue.

'__future__' looks like the proper solution, which is more like static language mechanism to load all type definition in advance, I will study and try it. But Do you think it will be much better if python interpreter stick to the basic statement of PEP3107 not to evaluate annotation expressions and let static validation tool like mypy to do the static validation?
Reply
#6
I don't think that's the basic statementof PEP 3107 at all. The basic statement, as provided in the Rationale, is to provide a standard way of specifying the information. That's it. All it says about evaluation is that it will be evaluated normally. Which makes sense to me.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#7
Okay, if like this, maybe Python strategy is going to be more like a language with strong type validation.

Anyway, I will try '__future__' if could solve my problem, thank you!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  I'm getting a NameError: ...not defined. vonArre 2 171 Mar-24-2024, 10:25 PM
Last Post: vonArre
  Decorators @ annotation drcl 3 337 Feb-24-2024, 06:12 AM
Last Post: Gribouillis
  Variable is not defined error when trying to use my custom function code fnafgamer239 4 516 Nov-23-2023, 02:53 PM
Last Post: rob101
  Printing the variable from defined function jws 7 1,165 Sep-03-2023, 03:22 PM
Last Post: deanhystad
Question How to annotation type? gamecss 4 946 Jul-27-2023, 03:03 AM
Last Post: gamecss
  Getting NameError for a function that is defined JonWayn 2 1,056 Dec-11-2022, 01:53 PM
Last Post: JonWayn
Question Help with function - encryption - messages - NameError: name 'message' is not defined MrKnd94 4 2,776 Nov-11-2022, 09:03 PM
Last Post: deanhystad
  How to print the output of a defined function bshoushtarian 4 1,237 Sep-08-2022, 01:44 PM
Last Post: deanhystad
  [split] NameError: name 'csvwriter' is not defined. Did you mean: 'writer'? cathy12 4 3,203 Sep-01-2022, 07:41 PM
Last Post: deanhystad
  NameError: name ‘app_ctrl’ is not defined 3lnyn0 0 1,457 Jul-04-2022, 08:08 PM
Last Post: 3lnyn0

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020