-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
sqlite3.Row behaves like a dictionary but doesn't handle "in" as one might expect #100450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm no expert, but it looks reasonable/intentional to me. What are the members of a row? I'd say the values, not the keys. The values are also what you get when you iterate a row. Yes, this prints
But this prints
And that's what you should expect. @sobolevn Does the latter still work with your |
But the |
I also think that checking values in mapping-like-structure with But, checking what fields are there - looks like a valid task. Because fields might be conditional. |
Do you mean intuituve? Why counter-intuitive? If you do an Internet search for "python if key in dict", you see lots of results like this: https://stackoverflow.com/questions/1602934/check-if-a-given-key-already-exists-in-a-dictionary and of course in the official docs https://docs.python.org/3/tutorial/datastructures.html#dictionaries all of which suggest using 'key in dict' where a dict is, of course, a mapping-like structure as you describe it.
Well, I raised the issue because I came across a use case for it: in a UI, I have a list of attributes associated with a row which are either keys in the row, or named functions to call with the row as argument to compute values from the row. So I was trying to do something along the lines of if key in row:
value = row[key]
else:
value = function_map[key](row) Obviously, I was able for my use case to switch things around: if key in function_map:
value = function_map[key](row)
else:
value = row[key] But that just underscores that using |
@vsajip sorry, I might used some wrong wording. I completely agree with you. Just to be clear:
🙂 |
The issues archive hints that there are not very many use cases for this feature; I could not find a single issue, other than this :) I of course agree that using By default, a cursor will return a resulting row as a BTW, if you need an actual |
There's always a first time any genuine issue is reported 🙂 I assume the missing I've used SQLite before through various wrappers/ORMs like SQLAlchemy, Peewee, Django etc. and so never had to use I didn't try the |
To expand on my thoughts on the proposed change of row membership testing from checking row values to instead checking column names: Container invariantSimple concept: Everything in the row ... should be in the row. In Python: for a in container:
assert a in container # this should ALWAYS be true The proposed change would violate that. And if you're thinking of also changing iteration to give column names instead of row values: iteration giving row values really can't be deemed not a valid use-case, as that's even suggested in the guides. Backwards incompatibilityBeing a backwards incompatible change possibly breaking existing programs, I think PEP 387 applies. So the change "should have a large benefit to breakage ratio", which has not been demonstrated. The "large benefit" shown so far is being able to write Nature of the dataRelational database (query) rows are conceptually different from general-purpose dicts. Note I keep saying "column names", not "keys" (anymore). Even the The For dicts, keys really are data, and in the dict. For example you might use a dict to count how often each word occurs in a text. Then the keys are the words, absolutely data. They come from the input data (the text). Not from the author of the program. For a relational database on the other hand, the column names are normally defined once by whoever created the table, before entering any data. |
The whole point of |
@vsajip I'd say I agree with most of that :-). Just shouldn't break the |
@sobolevn What did you mean with "conditional" fields? |
I haven't used So, I guess the same rule might be applied here, these two cases will create different row structures:
For some cases, we might be interested in some specific fields and their presence: like But, I don't have strong feelings about either decision. I see pros and cons in both of them. |
Hmm I don't quite get it. With |
You're assuming the person who wrote the query is the same person that's using the results, or it's in the same context. That's not always the case. A query might be generated dynamically (with differing result columns each time) and hand off results to be processed by some other module that didn't generate the query.
If it looks somewhat like a duck and quacks somewhat like a duck ... |
That's certainly possible :) It might also be a deliberate decision.
Not at all; it is not unreasonable to question why Putting my conservative hat on, I'd say that Hyrum's Law applies.
Try extracting the class generator as a helper function, and decorate that helper with |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
I'm not sure about that. It's not just an implementation detail, which I think Hyrum's law is about. The
So it does mention iteration and doesn't mention membership testing, which means membership testing is done by iteration, as that's its documented fallback when there's no explicit support via It doesn't say what data the iteration yields, but the documentation's So membership testing in a Edit: somewhat nevermind, I forgot that the |
I concur with @pochmann. If we want to go such far with breaking compatibility and turning If you want to check if the key is contained in the |
Those deprecations would break pretty much all sqlite3 code. I don't think that's a path we would like to follow.
That is easily fixable. (See #108558) |
I'm closing this as per feedback on Discourse. |
The
sqlite3.Row
class is supposed to give access to row results by name as well as index. So in some respects it behaves like a dictionary (it even has akeys()
method) but it doesn't appear to handle thein
operator as one might expect.The following minimal script illustrates:
prints
One would reasonably expect
k in row
to beTrue
.Tested on Python 3.10.0, Ubuntu 20.04, but not believed to be restricted to those.
Linked PRs
sqlite.Row.__contains__
method #100457The text was updated successfully, but these errors were encountered: