0

I'm trying to make a subclass with a @classmethod that would take as arguments an instance of its superclass and kwargs for its other fields. The goal is to be able to take an object of the general class and "extend" it into an object of the subclass.
Doing this, I've noticed a behavior of VSCode which I don't understand: When writing a @classmethod, the cls argument does not provide the argument hinting that calling the class constructor directly does.

Consider the following example:

import dataclasses
from typing import Self

@dataclasses.dataclass(kw_only=True)
class A:
    x: int

@dataclasses.dataclass(kw_only=True)
class B(A):
    y: int

    @classmethod
    def from_a_1(cls, a: A, y: int) -> Self:
        return cls(x=a.x, y=y) # cls() does not show argument hints

    @classmethod
    def from_a_2(cls, a: A, y: int) -> 'B':
        return B(x=a.x, y=y) #  B() does show hints just fine

a = A(x=1)
b_1 = B.from_a_1(a=a, y=2)
b_2 = B.from_a_2(a=a, y=2)

As the image on the left shows, for a direct class call B() it is possible to Trigger Parameter Hints, and also keyword arguments are shown in Trigger Suggest. The image on the right shows that the other variant, calling cls() makes Trigger Parameter Hints totally unavailable, and it does not show keyword arguments in Trigger Suggest.

argument hint show for direct class callargument hint not shown for call using cls

This prompted me to think that perhaps I don't have a good understanding of using classmethods, or that something about this confuses VSCode. What is the difference between those two different ways of doing (in this case) the same thing?

Furthermore, are b_1 and b_2 really the same thing / do those 2 approaches lead to same results?

Also to address the possible XY problem, what is the proper/reasonable/pythonic way to (take object of superclass) -> (make it into an object of subclass and fill the extra fields)?

2
  • 2
    Here's the question to ask: what is the static type of cls? There's no type hint, and statically there's no connection between the definition of from_a_1 and how you assume it will be called at runtime. (Further, the fact that from_a_1 will be bound to an instance of classmethod rather than the function defined by the def statement isn't something you can know statically; it requires an assumption about what classmethod is bound to and will do at runtime.) Commented Jan 11, 2024 at 15:54
  • if you have another class that extends B, class C(B): pass, then you can call C.from_a_1(a, y) and cls will be C, not B Commented Jan 24, 2024 at 21:36

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.