14

Trying to refer a class inside itself. For e.g.

class Test:
    FOO_DICT = {1 : Test.bar}  # NameError: name 'Test' is not defined

    @staticmethod
    def bar():
        pass

Does this usage make sense? Any better alternatives? Thanks!

cheng
  • 6,596
  • 6
  • 25
  • 27

3 Answers3

8

You don't need to reference the class inside itself, using bar instead of Test.bar will work fine.

class Test:
    @staticmethod
    def bar():
        pass

    FOO_DICT = {1: bar}


# You can access this outside of the class by simply using Test.FOO_DICT
print(Test.FOO_DICT)

However, there are cases where you really need to use a class in itself. For example

class Test:
    @staticmethod
    def bar():
        pass

    def test_with_other_of_same_instance(self, other: Test):
        print(other.FOO_DICT)

    FOO_DICT = {1: bar}

In this case,

  • I want to define a method that accepts an object of the same Test class.
  • I want to use python's type hinting to indicate that the expected argument is an instance of Test. This allows me get editor support and also so tools like pylance and mypy can notify me of possible errors if I passed a argument of wrong data type.

As at the time of this writing, I'll get a NameError: name 'Test' is not defined.

This is because by default I can't use a class within itself (It is possible later versions of python will change its default behavior, hence we won't be needing the solution below by that time).

But if you use Python versions from 3.7+ and you can't reference a class within itself, the simple solution came with PEP 563 - Postponed evaluation of annotations. It is implemented by adding a little line of code at the first line of the file

from __future__ import annotations
# other imports or code come afterwards


class Test:
    @staticmethod
    def bar():
        pass

    def test_with_other_of_same_instance(self, other: Test):
        print(other.FOO_DICT)

    FOO_DICT = {1: bar}

So you can use a class within itself in python by simply including that line at the beginning of the file.

Normally, if you use pylance or any similar tool, you get a warning or error display to show you that you imported something and didn't use it. But not in the case of annotations. You don't have to worry about any warning from your editor.

Note that this must occur at the beginning of the file otherwise you get a SyntaxError and versions earlier than 3.7 won't support this.

Victory Ifebhor
  • 101
  • 1
  • 4
5

If you want the dictionary to be in the class: define the function first and remove Test:

class Test:
    @staticmethod
    def bar():
         pass

    FOO_DICT = {1: bar}
Tom Malkin
  • 2,134
  • 2
  • 19
  • 35
  • Probably should avoid the ordering dependency, but there doesn't seem to be a better pattern. – cheng Dec 13 '16 at 22:20
0

You could move FOO_DICT = {1 : Test.bar} outside of class like this:

class Test:
    @staticmethod
    def bar():
         pass
Test.FOO_DICT = {1: Test.bar}
Apoorv Kansal
  • 3,210
  • 6
  • 27
  • 37