1

I'm writing a library containing an object that allows for method chaining on some of its methods. I'd like to provide users of this library with an easy way to know if any specific method supports chaining (and "users" includes IDEs that offer auto-completion).

According to this question and this question, chaining is easily accomplished by returning self at the end of the method call(s) that support chaining.

However, neither of those questions address how to indicate to a user that a method supports chaining (aside from the obvious docstring comment). As shown in the example code below, I tried to add a type hint, but since the class A isn't fully defined by the time I try to use it in a type hint, Python fails to instantiate an instance of the class.

class A():

    def chain(self) -> A:  # `self` is of type A, so `-> A` is an appropriate return type
        print("Chaining!")
        return self        # Enable method chaining
>>> A().chain().chain().chain()       # Should print "Chaining!" three times.
Traceback (most recent call last):
  File "scratch.py", line 1, in <module>
    class A():
  File "scratch.py", line 3, in A
    def chain(self) -> A:
NameError: name 'A' is not defined

What is an effective way to indicate that a method supports chaining in Python?

An ideal answer will use type hints or some other construct that allows IDEs to support auto-completion.

martineau
  • 119,623
  • 25
  • 170
  • 301
thehale
  • 913
  • 10
  • 18
  • Use this: `def chain(self) -> "A":` – crissal Feb 11 '22 at 20:41
  • @crissal Brilliant! Can you post a formal answer with a link to where that syntax is described so I can give you credit for the solution? – thehale Feb 11 '22 at 20:43
  • @PranavHosangadi Yes. However, I didn't find [that question](https://stackoverflow.com/q/33533148/14765128) in my initial search of SO since I was focused on the context of method chaining. That said, I personally prefer the answer on [this variant](https://stackoverflow.com/a/38341145/14765128) of that question because it links to the [official PEP](https://www.python.org/dev/peps/pep-0484/#forward-references) that explains this syntax. – thehale Feb 11 '22 at 21:04

2 Answers2

3

You can use your class in type hints, according to this excellent post, using your class as string.

In this case, you will need to modify your function signature as the following:

def chain(self) -> "A":
crissal
  • 2,547
  • 7
  • 25
  • The community likes to consolidate information in one place, so if you think this question is a duplicate of your linked question, please flag / vote as such instead of adding an answer. – Pranav Hosangadi Feb 11 '22 at 20:52
  • @PranavHosangadi The question linked by crissal does indeed contain the solution to this question, but it doesn't address the context of method chaining that I was seeking here. As such, I feel like this question still has value as a "signpost" for people like me who discover this type-hint conundrum from a method chaining perspective. – thehale Feb 11 '22 at 21:00
1
class A():
    def chain(self) -> 'A':  # `self` is of type A, so `-> A` is an appropriate return type
        print("Chaining!")
        return self

A().chain().chain().chain()

In your code A is not defined in quotes so it is counted as a variable

Jack Deeth
  • 3,062
  • 3
  • 24
  • 39
Rahul Das
  • 11
  • 2