Python mypy stati c типизация: принимать только аргументы Dict (с ключом str), списков (но не настраиваемых классов) и вложенных Dicts и Lists - PullRequest
0 голосов
/ 14 июля 2020

Я хочу, чтобы функция принимала аргумент стиля YAML, который может быть либо списком, либо dict. например,

foo({'a' : 1}), или foo([{'a' : 1}, {'b' : 2, 'c' : [1,2]}]), или foo({'a' : {'b' : 1}})

Если это dict, ключ должен быть строкой, а значение должно быть Union[int, float, str] , их список, другой словарь с теми же правилами ввода, что и он сам, или список словарей с такими же правилами. Если это список, это может быть список Union[int, float, str], список dicts или список списков с теми же правилами, что и он сам.

Никакие настраиваемые классы не должны быть разрешены, и ключ для любого dict должен быть строкой.

Я мог бы просто сделать:

def foo(yaml_args : Union[List[Any], Dict[str, Any]):
    pass

Но я хочу избежать использования Any.

Моя лучшая попытка на данный момент:

from typing import Dict, List, Union

ScalarPod = Union[int, float, str]
Pod = Union[ScalarPod, List[ScalarPod]]

NestedDict = Dict[str, Union[
    Pod,
    Dict[str, Union[
        Pod,
        Dict[str, Union[
            Pod,
            Dict[str, Pod]
        ]]
    ]]
]]

def foo(yaml_args : NestedDict):
    print(str(yaml_args))
    
foo({
        'number' : 1,
        'number_list' : [1, 2, 3],
        'dict_a' : 
        {
            'number_list_b' : [2,3,4],
            'number_b' : 3 
        },
        'dict_b' :
        {
            'nested_dict' :
            {
                'number' : 1,
                'number_b' : 2,
            }
        },
        'dict_c' :
        {
            'nested_dict' :
            {
                'nested_2_dict' : 
                {
                    'number' : 1
                }
            }
        },
        'dict_list' : [
            {
                'a' : 1
            },
            {
                'b' : 2
            }
        ]
    }
)

Это работает отдельно от списка диктовок, которые я, кажется, не могу исправить.

У него также есть недостаток, заключающийся в том, что он ограничен максимальной глубиной 3 вложенных диктовок, но это не не убийца игр. Я бы предпочел, чтобы у него была неограниченная глубина, но это не является обязательным требованием.

Как я могу этого добиться? Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 14 июля 2020

Я нашел способ упростить поддержку более глубоких вложенных dicts, но все еще не списков dicts:

ScalarPod = Union[int, float, str]
Pod = Union[ScalarPod, List[ScalarPod]]
PodDict = Dict[str, Pod]

T = TypeVar("T")

NestedDict = Dict[str, Union[
    Pod,
    T
]]

NestedDict = NestedDict[NestedDict[NestedDict[NestedDict[NestedDict[NestedDict[PodDict]]]]]]

a : NestedDict = {
        'number' : 1,
        'number_list' : [1.1, 2, 3],
        'dict_a' : 
        {
            'number_list_b' : [2,3,4],
            'number_b' : 3 
        },
        'dict_b' :
        {
            'nested_dict' :
            {
                'number' : 1,
                'number_b' : 2,
            }
        },
        'dict_c' :
        {
            'nested_dict' :
            {
                'nested_2_dict' : 
                {
                    'number' : 1
                }
            }
        }
    }
0 голосов
/ 14 июля 2020

Mypy - это программа проверки типов c. Ваша входная переменная может быть двух типов, как вы только что указали в своем первом предложении. Поэтому он не имеет типа stati c (неизменяемого).

Возможное решение: разделите входную переменную на две переменные с разными типами и добавьте значение по умолчанию None. Затем в вашей функции проверьте, какая переменная не равна none, и затем вы можете использовать ее.

...