简体   繁体   中英

How can I make the return-type of a function taking a sequence as input dependent on that sequences types?

I am working on a library able to perform SNMP set operations. There is a function that has a signature like the following:

def multiset(ip: str, community: str, oids: List[str], values: List[SnmpValue]) -> List[SnmpValue]:
   ...

This is slightly altered to the real signature to illustrate the typing issue a bit better. On normal operations, the function will return the values that were set back as list of the same types. In this example that looks redundant, but in the real code there is a use-case for this (error-detection), but that would make this typing question a bit too convoluted.

The core is that I have a function that takes a sequence of values and returns a sequence of the same types. The types are only really visible on a line that calls that function.

Another way to illustrate this is the code example below:

from typing import Generic, TypeVar, Union, List


TSupportedTypes = Union[int, str]
T = TypeVar('T', bound=TSupportedTypes)


class Wrapper(Generic[T]):

    def __init__(self, value: T) -> None:
        self.value = value



def process(data: List[Wrapper[TSupportedTypes]]) -> List[TSupportedTypes]:
    output = []
    for item in data:
        output.append(item.value)
    return output


processed = process([Wrapper(1), Wrapper('foo')])

# Is it possible to make this work without an "isinstance" check?
processed[1].startswith('f')

In the last time, the type-checker only knows that each value in the list is either an int or a str . In that case, the types are only known at the time process is called.

In the above case, the type-checker complains that int has no attribute startswith , but the code would work nonetheless.

Is there a way to tell the type-checker that whatever returns from the process function is the same as that what went into it?

Currently I use a healthy dose of Any hints, but that defeats a good part of the type-checking in this code and I would be really curious to find out if this works.

The problem isn't process or even Wrapper . The problem is that the list type is considered a homogeneous container type.

List[X] means every element of the list is an instance of the same X.

Even this simplified version of your example doesn't type check:

from typing import Union, List

TSupportedTypes = Union[int, str]
processed: List[TSupportedTypes] = [1, 'foo'] 

# Is it possible to make this work without an "isinstance" check?
processed[1].startswith('f')

You can see that for the particular value in this program, processed[1].startswith is safe but if you look at only the types - which is what mypy does - then there is no way to know this. According to the types processed[1] could be either a str or an int.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM