python: how to refer to the class from within it ( like the recursive function)

后端 未结 13 1766
旧时难觅i
旧时难觅i 2020-12-10 10:10

For a recursive function we can do:

def f(i):
  if i<0: return
  print i
  f(i-1)

f(10)

However is there a way to do the following thin

相关标签:
13条回答
  • 2020-12-10 10:40

    If I understand your question correctly, you should be able to reference class A within class A by putting the type annotation in quotes. This is called forward reference.

    class A:
      # do something
      def some_func(self, a: 'A')
      # ...
    

    See ref below

    1. https://github.com/python/mypy/issues/3661
    2. https://www.youtube.com/watch?v=AJsrxBkV3kc
    0 讨论(0)
  • 2020-12-10 10:40

    Nope. It works in a function because the function contents are executed at call-time. But the class contents are executed at define-time, at which point the class doesn't exist yet.

    It's not normally a problem because you can hack further members into the class after defining it, so you can split up a class definition into multiple parts:

    class A(object):
        spam= 1
    
    some_func(A)
    
    A.eggs= 2
    
    def _A_scramble(self):
        self.spam=self.eggs= 0
    A.scramble= _A_scramble
    

    It is, however, pretty unusual to want to call a function on the class in the middle of its own definition. It's not clear what you're trying to do, but chances are you'd be better off with decorators (or the relatively new class decorators).

    0 讨论(0)
  • 2020-12-10 10:40

    It's ok to reference the name of the class inside its body (like inside method definitions) if it's actually in scope... Which it will be if it's defined at top level. (In other cases probably not, due to Python scoping quirks!).

    For on illustration of the scoping gotcha, try to instantiate Foo:

    class Foo(object):
        class Bar(object):
            def __init__(self):
                self.baz = Bar.baz
            baz = 15
        def __init__(self):
            self.bar = Foo.Bar()
    

    (It's going to complain about the global name 'Bar' not being defined.)


    Also, something tells me you may want to look into class methods: docs on the classmethod function (to be used as a decorator), a relevant SO question. Edit: Ok, so this suggestion may not be appropriate at all... It's just that the first thing I thought about when reading your question was stuff like alternative constructors etc. If something simpler suits your needs, steer clear of @classmethod weirdness. :-)

    0 讨论(0)
  • 2020-12-10 10:42

    If the goal is to call a function some_func with the class as an argument, one answer is to declare some_func as a class decorator. Note that the class decorator is called after the class is initialized. It will be passed the class that is being decorated as an argument.

    def some_func(cls):
        # Do something
        print(f"The answer is {cls.x}")
        return cls # Don't forget to return the class
    
    @some_func
    class A:
        x = 1
    

    If you want to pass additional arguments to some_func you have to return a function from the decorator:

    def some_other_func(prefix, suffix):
        def inner(cls):
            print(f"{prefix} {cls.__name__} {suffix}")
            return cls
        return inner
    
    @some_other_func("Hello", " and goodbye!")
    class B:
        x = 2
    

    Class decorators can be composed, which results in them being called in the reverse order they are declared:

    @some_func
    @some_other_func("Hello", "and goodbye!")
    class C:
        x = 42
    

    The result of which is:

    # Hello C and goodbye!
    # The answer is 42
    
    0 讨论(0)
  • 2020-12-10 10:44

    Do remember that in Python, type hinting is just for auto-code completion therefore it helps IDE to infer types and warn user before runtime. In runtime, type hints almost never used(except in some cases) so you can do something like this:

    from typing import Any, Optional, NewType
    
    LinkListType = NewType("LinkList", object)
    
    
    class LinkList:
        value: Any
        _next: LinkListType
    
        def set_next(self, ll: LinkListType):
            self._next = ll
    
    
    if __name__ == '__main__':
        r = LinkList()
        r.value = 1
        r.set_next(ll=LinkList())
        print(r.value)
    

    And as you can see IDE successfully infers it's type as LinkList:

    Note: Since the next can be None, hinting this in the type would be better, I just didn't want to confuse OP.

    class LinkList:
        value: Any
        next: Optional[LinkListType]
    
    
    0 讨论(0)
  • 2020-12-10 10:46

    In Python you cannot reference the class in the class body, although in languages like Ruby you can do it.

    In Python instead you can use a class decorator but that will be called once the class has initialized. Another way could be to use metaclass but it depends on what you are trying to achieve.

    0 讨论(0)
提交回复
热议问题