如何在不使用 "isinstance" 的情况下告诉 PyCharm 一个对象是一个类型的特化(子类)?
How can I tell PyCharm that an object is a specialization (subclass) of a type without using "isinstance"?
我有一个方法可以接收共享一个公共超类但具有许多不同子类型的对象。它检查每个对象的类型,并根据类型将其传递给不同的函数。接收器函数被注释为接收特定的子类型。
对象类型是提前知道的并且是有限集的一部分。对象只会是 depth-1 sub类,而不是 sub-sub类.
此代码对性能非常关键。为了避免在调度时多次调用 isinstance
的开销,我将类型存储在一个变量中。
但是,我无法让 PyCharm 根据存储的类型变量检测每个对象的“专业化”。它指示类型错误,因为我将其类型仅作为超类知道的对象传递给接收特定 sub类.
的函数
例如,我的代码如下所示:
class Superclass: ...
class Subtype1(Superclass): ...
class Subtype2(Superclass): ...
# ...many more subtypes
def receiver1(arg: Subtype1): ...
def receiver2(arg: Subtype2): ...
# ...many more receivers
def dispatch():
item = get_item()
item_type = type(item)
if item_type is Subtype1:
receiver(item)
elif item_type is Subtype2:
receiver2(item)
# ... many more cases
使用该代码,PyCharm 检测到对 receiver1
和 receiver2
的调用的类型不匹配。
通常,我会在这里放弃,因为 Python 是一种动态类型的语言,坚持 IDE 在结构上理解调度动态类型的代码似乎是不合理的。
但是,PyCharm 可以进行该专业化;它似乎只适用于 isinstance
检查。如果我用下面的代码替换 dispatch
,PyCharm 类型检查正确:
def dispatch():
item = get_item()
if isinstance(item, Subtype1):
receiver1(item)
elif isinstance(item, Subtype2):
receiver2(item)
# ... many more cases
问题是,那太慢了。 isinstance
本身比 is
比较慢得多,我必须多次调用它来检查每个案例;有很多情况。
有没有办法让 PyCharm 在不使用 isinstance
的情况下检测简单的专业化类型?如果是,怎么做?
我试过的
- 通常,这很适合面向对象。如果
receiver
函数是每个子类型的方法,我每次都可以简单地调用 item.recieve()
或其他东西。但是,子类型是在我无法控制的代码中声明的(并且是在 C 中实现的记录 类,因此它们不能被子类化——我知道这很奇怪,但我确实否认它是性能关键代码:)).
- 各种调度 table 方法使用
dict
以类型为键,接收方方法作为值同样击败了 PyCharm 的类型检查。
您可以为 PyCharm
提供额外的类型提示
def dispatch():
item = get_item()
item_type = type(item)
if item_type is Subtype1:
item: Subtype1
receiver1(item)
elif item_type is Subtype2:
item: Subtype2
receiver2(item)
这应该不会影响代码的性能。
另一种方法是将接收器方法注入 Subtype1/2 类:
def receiver1(arg: Subtype1):
print("receiver1 called")
def receiver2(arg: Subtype2):
print("receiver2 called")
class MyMeta(type):
pass
d = dict(Subtype1.__dict__)
d.update({"receiver": receiver1})
Subtype1 = MyMeta(Subtype1.__name__,
Subtype1.__bases__,
d)
d = dict(Subtype2.__dict__)
d.update({"receiver": receiver2})
Subtype2 = MyMeta(Subtype2.__name__,
Subtype2.__bases__,
d)
def dispatch():
item = get_item()
item.receiver()
我有一个方法可以接收共享一个公共超类但具有许多不同子类型的对象。它检查每个对象的类型,并根据类型将其传递给不同的函数。接收器函数被注释为接收特定的子类型。
对象类型是提前知道的并且是有限集的一部分。对象只会是 depth-1 sub类,而不是 sub-sub类.
此代码对性能非常关键。为了避免在调度时多次调用 isinstance
的开销,我将类型存储在一个变量中。
但是,我无法让 PyCharm 根据存储的类型变量检测每个对象的“专业化”。它指示类型错误,因为我将其类型仅作为超类知道的对象传递给接收特定 sub类.
的函数例如,我的代码如下所示:
class Superclass: ...
class Subtype1(Superclass): ...
class Subtype2(Superclass): ...
# ...many more subtypes
def receiver1(arg: Subtype1): ...
def receiver2(arg: Subtype2): ...
# ...many more receivers
def dispatch():
item = get_item()
item_type = type(item)
if item_type is Subtype1:
receiver(item)
elif item_type is Subtype2:
receiver2(item)
# ... many more cases
使用该代码,PyCharm 检测到对 receiver1
和 receiver2
的调用的类型不匹配。
通常,我会在这里放弃,因为 Python 是一种动态类型的语言,坚持 IDE 在结构上理解调度动态类型的代码似乎是不合理的。
但是,PyCharm 可以进行该专业化;它似乎只适用于 isinstance
检查。如果我用下面的代码替换 dispatch
,PyCharm 类型检查正确:
def dispatch():
item = get_item()
if isinstance(item, Subtype1):
receiver1(item)
elif isinstance(item, Subtype2):
receiver2(item)
# ... many more cases
问题是,那太慢了。 isinstance
本身比 is
比较慢得多,我必须多次调用它来检查每个案例;有很多情况。
有没有办法让 PyCharm 在不使用 isinstance
的情况下检测简单的专业化类型?如果是,怎么做?
我试过的
- 通常,这很适合面向对象。如果
receiver
函数是每个子类型的方法,我每次都可以简单地调用item.recieve()
或其他东西。但是,子类型是在我无法控制的代码中声明的(并且是在 C 中实现的记录 类,因此它们不能被子类化——我知道这很奇怪,但我确实否认它是性能关键代码:)). - 各种调度 table 方法使用
dict
以类型为键,接收方方法作为值同样击败了 PyCharm 的类型检查。
您可以为 PyCharm
提供额外的类型提示def dispatch():
item = get_item()
item_type = type(item)
if item_type is Subtype1:
item: Subtype1
receiver1(item)
elif item_type is Subtype2:
item: Subtype2
receiver2(item)
这应该不会影响代码的性能。
另一种方法是将接收器方法注入 Subtype1/2 类:
def receiver1(arg: Subtype1):
print("receiver1 called")
def receiver2(arg: Subtype2):
print("receiver2 called")
class MyMeta(type):
pass
d = dict(Subtype1.__dict__)
d.update({"receiver": receiver1})
Subtype1 = MyMeta(Subtype1.__name__,
Subtype1.__bases__,
d)
d = dict(Subtype2.__dict__)
d.update({"receiver": receiver2})
Subtype2 = MyMeta(Subtype2.__name__,
Subtype2.__bases__,
d)
def dispatch():
item = get_item()
item.receiver()