class A:
def __init__(self): ...
class BBuilder:
# To make this simpler, we won't have any arguments
def build(self): # -> WhatTypeHintDoIPutHere
class B(A):
def __init__(self):
super().__init__()
return B
my_b_builder: BBuilder = BBuilder()
BBuilt = my_b_builder.build() # BBuilt: WhatTypeHintDoIPutHere
my_b = BBuilt() # my_b: WhatTypeHintDoIPutHere
如何正确输入提示
my_b
和BBuilt
?无需删除 BBuilder,也无需用静态子类定义替换 BBuilder。
尝试输入提示
my_b
为:
Type[A] - 不正确,因为 my_b 是一个实例
类型[B] - 不正确,因为 my_b 是一个实例
BBuilt - mypy 抱怨 - 你不能在类型提示中使用变量
使用 TypeAliases
BBuiltAlias: TypeAlias = BBuilt; my_b: BBuiltAlias
- 您不能在类型提示中使用变量
使用
type
关键字 type BBuiltAlias = BBuilt; my_b: BBuiltAlias
- 您不能在类型提示中使用变量
将 BBuilder 编辑为不是数据类不会改变任何东西
还尝试了 TypeVars - 没有成功。尝试: 1 2 3
还尝试询问 ChatGPT - 没有成功
如果您真的需要它,这里是原始代码以及这些类的一些示例用法。作为一个附带问题:这样做是一种不好的编码习惯吗?原始代码易于编辑,易于使用。
题外话:我尝试解决这个问题失败了这里
即使这是可能的,动态创建类(根据很多人的说法)可能会带来一些令人讨厌的问题。可能还有其他方法可以在没有动态类定义的情况下解决您的问题!
答案其实非常简单。
from typing import Type
# To make this a little simpler, we will not define any arguments for the init functions.
# It would not be that hard if you wanted to introduce arguments
class ABase: # We want to subclass ABase and overwrite its init
def __init__(self) -> None: # We want to call this init in our dynamically created class!
print("ABase Init")
... # Imagine lots of code here
def uncool(self) -> None: # This method is uncool. We want our final subclass to overwrite it and make it cooler
print("Uncool (we should not see this message because its uncool and this method will be overwritten)")
def a_cool(self) -> None: # This method is cool! We want our final subclass to support it!
print("A_Cool Is there really no other way to solve your problem than creating classes dynamically?")
class BReal(ABase):
def __init__(self) -> None:
super().__init__()
print("BReal Init")
... # Imagine lots of code here
def b_cool(self) -> None: # This method is also cool! we want our final subclass to support it!
print("B_Cool")
def uncool(self) -> None:
print("Uncool is now cool because it has been overwritten! So we can now see its message!")
# Define all the methods and functionality you want the final dynamically-created Subclass to support
# Basically treat BReal almost as if it WAS the final dynamically-created Subclass
class BClassBuilder:
def build(self) -> Type[BReal]: # Since the B class is 100% compatible with BReal. There is no problem with using the Type[BReal] typehint
class B(BReal): ...
return B # Yay! B is now dynamically created
# KEEP IN MIND THIS IS JUST SOME BASIC PROOF-OF-CONCEPT CODE
# I KEPT THIS AS SIMPLE AS POSSIBLE
# But don't be fooled, this simple design took me a day to figure out
our_builder: BClassBuilder = BClassBuilder()
BBuilt: Type[BReal] = our_builder.build() # Since the B class is 100% compatible with BReal. There is no problem with using the `Type[BReal]` typehint
print("\nTesting Inits")
our_b: BReal = BBuilt() # Instance of our dynamically created B class!
print("\nTesting Methods")
our_b.a_cool() # InteliSense WORKED
our_b.b_cool() # InteliSense WORKED
our_b.uncool() # InteliSense WORKED
"""OUTPUT
Testing Inits
ABase Init
BReal Init
Testing Methods
A_Cool Is there really no other way to solve your problem than creating classes dynamically?
B_Cool
Uncool is now cool because it has been overwritten! So we can now see its message!
""" # EVERYTHING WORKS AND THERE ARE 0 COMPLAINTS FROM PYLANCE AND MYPY
由于示例中的注释数量较多,我认为没有必要进行太多解释。我将简要解释正在发生的事情:
首先我们将要子类化的类定义为
ABase
然后我们静态创建
ABase
的子类,名为 BReal
(“真实”,因为这实际上是您编写代码的部分)。我们动态创建的类将简单地子类化 BReal,因此继承它的所有方法和其他内容。
在现在的示例中,我们添加了一些动态定义类的方法。我选择了 Class Builder(这可能不是一个真正的术语,也不是一个专业术语)。
定义 A 的动态创建子类非常简单。我们将其命名为 B。
class B(BReal): ...
我们故意使用 ...,因为我们没有应该在这里编写真正的代码。
对于那些希望 B 在其 init 中支持参数的 Python 新手请注意:
由于我们定义 B 的方式使其成为 BReal 的 100% 子类,没有任何差异,因此它也继承了 BReal 的
init
!因此,如果您希望 B 支持参数,请编辑 BReal 的 init
。保留 B 的 init
未定义!
即使这是可能的,动态创建类(根据很多人的说法)可能会带来一些令人讨厌的问题。可能还有其他方法可以在没有动态类定义的情况下解决您的问题!
作为旁注。我觉得有点不满意,问题的解决方案是首先在全局范围内静态定义类,然后基本上“镜像”它