Why does mypy complain about my dictionary comprehension? - python

I'm trying to do an update of a dictionary with a dictionary comprehension. My code works fine, but mypy raises an error while parsing the types.
Here's the code:
load_result = {"load_code": "something"}
load_result.update({
quality_result.quality_code: [quality_result.quantity]
for quality_result in random_quality_results()
})
In that code the quality_result objects have those two attributes quality_code and quantity which are a string and a float respectively.
Here the code for those quality result objects:
class QualityResult(BaseSchema):
"""Asset quality score schema."""
quality_code: str
quantity: float = Field(
...,
description="Value obtained [0,1]",
ge=0,
le=1,
)
My code works as expected and returns the desired dictionary, but when running mypy it throws this error:
error: Value expression in dictionary comprehension has incompatible type "List[float]"; expected type "str"
I see mypy is getting the types correctly as I'm inserting a list of floats, the thing is I don't understand why it complains. I assume I must be missing something, but I'm not being able to figure it out.
Why does it say it must be a string? How can I fix it?

On the first line you write:
load_result = {"load_code": load}
load is a string and this code makes mypy assume that the type for load_result is going to be Dict[str, str]. Then later on you write you dictionary comprehension where your values are of type List[float].
Depending on what values you want in your dictionary, you can explicitly type it on the first line:
load_result: Dict[str, Union[str, List[float]]] = {"load_code": load}
or
load_result: Dict[str, Any] = {"load_code": load}

Related

automate index changing in a for loop

I have a JSON file that I extracted a list that I'm taking out of it.
I've tried to use list indexing to get the other items from the list but I'm getting this error.
TypeError: list indices must be integers or slices, not str.
for name in data['athletes'][0:]['athlete']['displayName']:
print(name)
If I don't use the colon in the indexing it extracts the first name.
You're specifying:
for name in data['athletes'][0:]['athlete']['displayName']:
print(name)
Presumably data['athletes'][0] is a dictionary. But by saying data['athletes'][0:], you are taking a slice of the data['athletes'] list, in essence copying the entire list. Trying to extract a key value 'displayName', which is a string, from a list make no sense and hence your error (you can only index lists by integers). Of course, that was not your intention. You just want the zeroth element of the list, so remove the colon.
If each element of the list, data['athletes'], is a dictionary with key athlete that you are trying to display, then see the answer posted by Daniel Roseman (#DanielRoseman).
You probably want:
for athlete in data['athletes']
print(athlete['athlete']['displayName']
but it's impossible to tell for sure without seeing your JSON.
This is the type of data, correct?
data: Dict[str, List[Dict[str, Dict[str, str]]]]
Hence:
data['athletes'][0]: Dict[str, Dict[str, str]]
data['athletes'][0:]: List[Dict[str, Dict[str, str]]]
When you slice data['athletes'] (via [0:]), you get the List, which you can't index via a string. When you get a particular element (via [0]), you get the first Dict inside the List.
Other answers have already suggested how to print the names. If you wanted to turn them into a list, here's how you could do it via comprehension (I think this is sort of what you're trying to do with the slice):
names = [entry['athlete']['displayName'] for entry in data['athletes']]

how to pass string as key in dictionary

i want to parse dictionary dynamically
here i'm trying to get the name of key dynamically and storing that key in variable and call dictionary using those variable
so far i tried this
var=users.to_dict()
z=var.keys()
y=z[0]
x=var[str(y)]['Scheme name']
when i pass str(y) it giving error
y=x[0]
TypeError: 'dict_keys' object does not support indexing
is there any better ways to this. please let me know
you cannot index 'dict_keys' but if you parse them to 'list'
var=users.to_dict()
z=list(var.keys())
y=z[0]
x=var[str(y)]['Scheme name']
it should work
y=z[0]
is where your error is.
var.keys() doesn't return a list, it returns a dict_keys, which doesn't support indexing. You can convert it to an list and then index:
y = list(x)[0]
However, z = list(var) will have the same effect (list of keys) and is a little more direct.
A dict_keys behaves this way because it's a view object. It's an iterable whose contents change if the underlying dictionary changes. The result of casting it as a list (or casting the dictionary as a list) is that it's no longer connected to dictionary.

How can I type multiple values returned from a method? [duplicate]

How do I use type hints to annotate a function that returns an Iterable that always yields two values: a bool and a str? The hint Tuple[bool, str] is close, except that it limits the return value type to a tuple, not a generator or other type of iterable.
I'm mostly curious because I would like to annotate a function foo() that is used to return multiple values like this:
always_a_bool, always_a_str = foo()
Usually functions like foo() do something like return a, b (which returns a tuple), but I would like the type hint to be flexible enough to replace the returned tuple with a generator or list or something else.
You are always returning one object; using return one, two simply returns a tuple.
So yes, -> Tuple[bool, str] is entirely correct.
Only the Tuple type lets you specify a fixed number of elements, each with a distinct type. You really should be returning a tuple, always, if your function produces a fixed number of return values, especially when those values are specific, distinct types.
Other sequence types are expected to have one type specification for a variable number of elements, so typing.Sequence is not suitable here. Also see What's the difference between lists and tuples?
Tuples are heterogeneous data structures (i.e., their entries have different meanings), while lists are homogeneous sequences. Tuples have structure, lists have order.
Python's type hint system adheres to that philosophy, there is currently no syntax to specify an iterable of fixed length and containing specific types at specific positions.
If you must specify that any iterable will do, then the best you can do is:
-> Iterable[Union[bool, str]]
at which point the caller can expect booleans and strings in any order, and of unknown length (anywhere between 0 and infinity).
Last but not least, as of Python 3.9, you can use
-> tuple[bool, str]
instead of -> Tuple[bool, str]; support for type hinting notation has been added to most standard-library container types (see PEP 585 for the complete list). In fact, you can use this as of Python 3.7 too provided you use the from __future__ import annotations compiler switch for your modules and a type checker that supports the syntax.

Variable method name in python

I have a dictionnary fields={} which contains some field names that I named the Qt comobox objects after. For example keys combobox1 and combobox2, both contain a list with values that I would like to add to the
fields={}
fields['combobox1']=['value1','someting else']
fields['combobox2']=['bla','another value']
for key,values in fields.items():
for value in values:
Qt_ui. _____key_____ .addItem(value)
what is the correct syntax for the last line, so that ____key____ is replaced with the keys from the dictionary? I tried ui.__getattribute__(key).addItem(value) but it does't seem to work. Any suggestions are appreciated.
TypeError: 'PySide.QtGui.QComboBox.addItem' called with wrong argument types:
PySide.QtGui.QComboBox.addItem(float)
Supported signatures:
PySide.QtGui.QComboBox.addItem(PySide.QtGui.QIcon, unicode, QVariant = QVariant())
PySide.QtGui.QComboBox.addItem(unicode, QVariant = QVariant())
In fact the problem was somewhere else getattribute(key) is correct but the added item needs to be a string. Any way, I thought this is an interesting problem and will leave the post anyway.
ui.__getattribute__(key).addItem(str(value))

Any way to use a tuple as key in a shelf? (Python)

I want to use a tuple (1,2,3) as a key using the shelve module in Python. I can do this with dictionaries:
d = {}
d[(1,2,3)] = 4
But if i try it with shelve:
s = shelve.open('myshelf')
s[(1,2,3)] = 4
I get: "TypeError: String or Integer object expected for key, tuple found"
Any suggestions?
How about using the repr() of the tuple:
s[repr((1,2,3))] = 4
As per the docs,
the values (not the keys!) in a shelf
can be essentially arbitrary Python
objects
My emphasis: shelf keys must be strings, period. So, you need to turn your tuple into a str; depending on what you'll have in the tuple, repr, some separator.join, pickling, marshaling, etc, may be fruitfully employed for that purpose.
Why not stick with dictionaries if you want to have arbitray keys ? The other option is to build a wrapper class around your tuple with a repr or str method to change it to a string. I am thinking of a library(natural response to shelves) - your tuple can be the elements in the Dewey decimal and the str creates a concatenated complete representation.
This may be an old question, but I had the same problem.
I often use shelve's and frequently want to use non-string keys.
I subclassed shelve-modules class into a shelf which automatically converts non-string-keys into string-keys and returns them in original form when queried.
It works well for Python's standard immutable objects: int, float, string, tuple, boolean.
It can be found in: https://github.com/North-Guard/simple_shelve

Categories

Resources