-2

In Python, when I'm defining a function inside a class, I can include self as one of the arguments to access the member variables of that class, and I can also choose not include self as the argument if I don't need to access its member variables. But then I discovered that if the function does not have self as arguments, then it becomes invisible to other functions in that class. For example

class Test:
    def __init__(self, val:int) -> None:
        self.a = val
    def f(a:int) -> int:
        return a + 1
    def g(self) -> int:
        return f(self.a)

if __name__ == '__main__':
    t = Test(2)
    print(t.g())

The above codes will lead to the following error message:

Traceback (most recent call last):
  File "/Users/louchenfei/Downloads/lc.py", line 11, in <module>
    print(t.g())
  File "/Users/louchenfei/Downloads/lc.py", line 7, in g
    return f(self.a)
NameError: name 'f' is not defined

I wonder why that's the case and what are the rules for visibilities of functions defined in a class?

  • 2
    The names of the function's arguments are completely irrelevant; you simply aren't telling Python to find the function in the class. A plain `f()` looks for the name as a local or global variable; you'd have to write `Test.f()` to look it up in the class. – jasonharper Aug 27 '22 at 21:11
  • 3
    Welcome to Stack Overflow. Please try to test your assumptions first before describing the problem. Notice that `return f(self.a)` causes the same `NameError` even if `f` has a `self` argument. The name `self` is **not special**. – Karl Knechtel Aug 27 '22 at 21:16

1 Answers1

0

Its difficult to know what you want, but one solution is to make f a staticmethod. Still you need to have a reference to Test in some way:

class Test:
    def __init__(self, val:int) -> None:
        self.a = val
    @staticmethod
    def f(a:int) -> int:
        return a + 1
    def g(self) -> int:
        return self.f(self.a)

if __name__ == '__main__':
    t = Test(2)
    print(t.g())

Here, the call is self.f(self.a).

The method f is not in scope inside another method.

quamrana
  • 37,849
  • 12
  • 53
  • 71
  • I think it's clear what they want: They want to know the rule that says that they have to refer to `f` as `self.f` from `g`. – mkrieger1 Aug 27 '22 at 21:16
  • @mkrieger1: Its never clear what the OP really wants. They *could* actually need a free function `f`. I'm suggesting using `staticmethod` as possibly the smallest change to get running code. – quamrana Aug 27 '22 at 21:18
  • Thanks. I did not realize `f` is not in scope of other functions and I have to use `Test.f()` or `staticmethod` to access it. – Chenfei Lou Aug 27 '22 at 21:32
  • Yes, in fact, maybe `Test.f()` would be simpler, but it is unconventional to define `f()` as you have it. The conventions are: 1. `f(self)` 2. `@staticmethod` 3. `@classmethod` (probably not useful here) – quamrana Aug 27 '22 at 21:34
  • You may want to revert edit your question back to edit number 2. I think that is closest to how you were thinking about methods in classes. – quamrana Aug 27 '22 at 21:36
  • `f` is not in the scope of **any** function. There isn't a separately existing `f`, only an *attribute* `f` of the `Test` class. It is the same as how there is no built-in `upper`, only an attribute of `str`. – Karl Knechtel Aug 27 '22 at 21:40