英文:
How do type a function in python based on the return value of a method on an instance passed in?
问题
在Python中,您可以使用继承和多态来实现类似的功能。以下是您示例的Python版本:
class DocumentSuperClass:
pass
class DocumentA(DocumentSuperClass):
pass
class DocumentB(DocumentSuperClass):
pass
# ... many more sibling classes
class SuperClass:
def __init__(self, doc):
self.doc = doc
def meth(self):
return self.doc
class A(SuperClass):
pass
class B(SuperClass):
pass
# ... many more sibling classes
def a(input):
return input.meth()
instanceOfDocumentA = a(A(DocumentA()))
instanceOfDocumentB = a(B(DocumentB()))
# ... same behavior for many more sibling classes
这段代码实现了与 TypeScript 示例类似的功能,根据传递给函数的实例的行为返回不同的值。
英文:
In TypeScript, I can define a function such that the return value is different depending on the behavior of an instance that was passed into the function. (See the example below.)
How can I do something similar in Python?
class DocumentSuperClass {
}
class DocumentA extends DocumentSuperClass {}
class DocumentB extends DocumentSuperClass {}
// ... many more sibling classes
class SuperClass {
doc: DocumentSuperClass
meth() {
return this.doc;
}
}
class A {
doc: DocumentA
meth() {
return this.doc;
}
}
class B {
doc: DocumentB
meth() {
return this.doc;
}
}
// ... many more sibling classes
function a<T extends SuperClass>(input: T) {
return input.meth() as ReturnType<T['meth']>;
}
const instanceOfDocumentA = a(new A());
const instanceOfDocumentB = a(new B());
// ... same behavior for many more sibling classes
答案1
得分: 1
以下是翻译好的部分:
你有几个选择:
使用 @overload
from dataclasses import dataclass
from typing import overload
@dataclass
class A:
val: int
@dataclass
class B:
val: str
@overload
def a(arg: A) -> int: ...
@overload
def a(arg: B) -> str: ...
def a(arg: A | B):
return arg.val
typed_as_int = a(A(123))
typed_as_str = a(B("abc"))
返回类型取决于传入的参数:
Foo().one() # -> Tuple[Any, ...] | None
Foo().one('tuple') # -> Tuple[Any, ...] | None
Foo().one('dict') # -> Dict[str, Any] | None
使用泛型
from typing import TypeVar
T = TypeVar('T')
def foo(arg: T) -> T:
return arg
foo(1) # -> int
foo('bar') # -> str
另一种替代方案:
可以使用 Union[]
类型,但这会使您的函数返回联合类型,而不是实际的运行时类型。
英文:
You've got a few options:
Use @overload
from dataclasses import dataclass
from typing import overload
@dataclass
class A:
val: int
@dataclass
class B:
val: str
@overload
def a(arg: A) -> int: ...
@overload
def a(arg: B) -> str: ...
def a(arg: A | B):
return arg.val
typed_as_int = a(A(123))
typed_as_str = a(B("abc"))
The return types depend on what's passed in:
Foo().one() # -> Tuple[Any, ...] | None
Foo().one('tuple') # -> Tuple[Any, ...] | None
Foo().one('dict') # -> Dict[str, Any] | None
Use generics
from typing import TypeVar
T = TypeVar('T')
def foo(arg: T) -> T:
return arg
foo(1) # -> int
foo('bar') # -> str
another alternative:
Could use Union[]
type, but that makes your function return the union type as well, not the actual runtime type.
答案2
得分: 0
你可以使用'singledispatch'用于函数,或者'singledispatchmethod'用于类方法。
此外,此代码通过了mypy检查,所以代码的类型注解是正确的。
from functools import singledispatch
class A:
def meth(self):
return 'a'
class B:
def meth(self):
return 1
C = A | B
@singledispatch
def function(input_: C):
pass
@function.register
def _(input_: A) -> str:
return input_.meth()
@function.register
def _(input_: B) -> int:
return input_.meth()
print(function(A()))
print(function(B()))
a
1
英文:
You can use 'singledispatch' for functions or 'singledispatchmethod' for class methods.
Also, this code passes mypy checks, so code's typing annotations are fine.
from functools import singledispatch
class A:
def meth(self):
return 'a'
class B:
def meth(self):
return 1
C = A | B
@singledispatch
def function(input_: C):
pass
@function.register
def _(input_: A) -> str:
return input_.meth()
@function.register
def _(input_: B) -> int:
return input_.meth()
print(function(A()))
print(function(B()))
a
1
答案3
得分: 0
这似乎有效。对我来说,奇怪的是我没有明确定义返回类型。但如果我只是将其未定义,类型提示器似乎能够解决问题:
class DocumentSuperClass:
pass
class DocumentA(DocumentSuperClass):
pass
class DocumentB(DocumentSuperClass):
pass
class SuperClass:
def __init__(self):
self.doc = DocumentSuperClass
def meth(self):
return self.doc
class ClassA(SuperClass):
def __init__(self):
self.doc = DocumentA()
def meth(self):
return self.doc
class ClassB(SuperClass):
def __init__(self):
self.doc = DocumentB()
def meth(self):
return self.doc
def func(input: SuperClass):
return input.meth()
instanceOfDocumentA = func(ClassA())
instanceOfDocumentB = func(ClassB())
英文:
This seemed to work. It's odd to me that I'm not defining the return type explicitly. But if I just leave it undefined, the type hinter seems to figure things out:
class DocumentSuperClass:
pass
class DocumentA(DocumentSuperClass):
pass
class DocumentB(DocumentSuperClass):
pass
class SuperClass:
def __init__(self):
self.doc = DocumentSuperClass
def meth(self):
return self.doc
class ClassA(SuperClass):
def __init__(self):
self.doc = DocumentA()
def meth(self):
return self.doc
class ClassB(SuperClass):
def __init__(self):
self.doc = DocumentB()
def meth(self):
return self.doc
def func(input:SuperClass):
return input.meth()
instanceOfDocumentA = func(ClassA())
instanceOfDocumentB = func(ClassB())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论