1

How to define a function, inside a class method (for example for a threading Thread target function), that needs access to self? Is the solution 1. correct or should we use 2.?

  1. import threading, time
    class Foo:
        def __init__(self):
            def f():
                while True:
                    print(self.a)                
                    self.a += 1
                    time.sleep(1)
            self.a = 1
            threading.Thread(target=f).start()
            self.a = 2
    Foo()
    

    It seems to work even if self is not a parameter of f, but is this reliable?

  2. import threading, time
    class Foo:
        def __init__(self):
            self.a = 1
            threading.Thread(target=self.f).start()
            self.a = 2
        def f(self):
            while True:
                print(self.a)                
                self.a += 1
                time.sleep(1)
    Foo()
    

This is linked to Defining class functions inside class functions: Python but not 100% covered by this question.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 2
    #2 might be considered more readable and maintainable, I'd just go with `def _f` to tell outside code it (probably) should not be called directly (as per the convention) – DeepSpace Jun 06 '23 at 14:35
  • 1
    #1 works because it's a [closure](https://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python) – DeepSpace Jun 06 '23 at 14:36
  • @DeepSpace In such contexts, are 1. and 2. the only patterns we see, or is there a (very common) third method that I haven't seen? Maybe `def __init__(self):` and inside: `def f(self):`. Is the latter possible inside `__init__`? – Basj Jun 06 '23 at 14:50

2 Answers2

2

The first is fine; f is redefined every time you call __init__, but as it is local to __init__, it has access to the entire local scope of __init__, including the name self.

Whether __init__ should be starting a new thread is another matter.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • About your last paragraph, yes in my real code, the thread is not started during `__init__`, here it is just for the purpose of the MCVE code. – Basj Jun 06 '23 at 19:19
1

Either way is reliable its mostly preference, nesting the f function within __init__ will allow it to have access to (thank you @DeepSpace) variables defined within __init__, putting it outside but passing self to it allows for the same thing. I don't believe there is a set "right" way to do this.