I have a class that defines its own __getattr__() in order to interact with an XML tree instantiated objects contain. This hides the XML structure from the user and allows him to set tag values, etc. as if they were normal fields on the object and works fine for all fields except for one: The one named field. Here's how it looks:
>>> q = MyQuery()
>>> q.file = "database"
>>> print(q)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<requestCollection xmlns="http://dwd.de/sky">
<read>
<select>
<referenceDate>
<value></value>
</referenceDate>
</select>
<transfer>
<file name="my file"/>
</transfer>
</read>
</requestCollection>
>>> q.file
That works fine, the side effects that should happen do so. But if I try to set the field field, I get a string that the method shouldn't be returning. For clarity, this is a simplified version of my __getattr__:
def __getattr__(self, key):
logging.info("Looking up value for key {}.".format(key))
if key == "something"
return self.method_with_side_effect(key)
if key in field_list:
logging.info("Key is in the field list.")
return self.other_method_with_side_effects(key)
ensemble_member and field are both in field_list. Check this out:
>>> q = MyQuery()
>>> q.ensemble_member
Looking up value for key __members__.
Looking up value for key __methods__.
Looking up value for key ensemble_member.
Key is in the field list.
... Side effects ...
>>> q.field
'station'
Looking up value for key __members__.
Looking up value for key __methods__.
The behavior for ensemble_member is correct, for field it's totally incorrect. Why is that?
I have no methods nor class / object members named field.
Another interesting thing is, if I put this on the first line of __getattr__:
def __getattr__(self, key):
if key == "field":
raise ValueError
The following still happens:
>>> q = MyQuery()
>>> q.field
'station'
Looking up value for key __members__.
Looking up value for key __methods__.
What's going on?
I've got it - the offending code was, in the end, these lines:
class SkyQuery(object):
_unique_fields = ["parameter",
"ensemble",
"forecast",
"station"]
_field_tag_values = [field + "_value" for field in _unique_fields]
Naming the temporary variable "field" in my list comprehension was causing the problem. Python was retaining it after I was done. This behavior is consistent, I just wasn't expecting it.
I see three solutions here (the third was suggested by user4815162342). I implemented the third.
Rename the temporary variable to x rather than field. Then I still have x as a temporary variable floating around in my code, but because no members should be called x it doesn't bother me.
Call del(field) to delete the field. I don't like calling del() and I thought it would clutter up my code, but it would work if I really needed to be able to access that variable later on.
replace the list comprehension with a generator expression list(field + "_value" for field in _unique_fields) which does not share this problem
Related
The reason I want to do this is to allow the user to create a file tree using a QTreeWidget, then I want to extract that tree in to a nested dict structure, and save it some how. I've thought about using a txt file and eval aproach to simply load all the saved schemes into some array or just another dict where the key is the name of the scheme, so the user can then simply select a scheme or edit it if they wish. This naturally leads to me having to then convert that saved dict back into a QTreeWidget after the user has selected edit.
For now though here's my problem.
I've been able to successfully navigate the QTreeWidget using a recursive a function. What I struggle with is the logic behind creating the nested dict.
Below is what i have come up with so far:
def tree_to_dict(self, parent, key):
for i in range(parent.childCount()):
cur_par = parent.child(i)
if cur_par.childCount() == 0:
try:
if type(self.scheme[key]) is dict :
self.scheme[key][cur_par.text(0)] = 'E'
except KeyError:
key = cur_par.text(0)
self.scheme[key] = 'E'
else:
key = cur_par.text(0)
self.scheme[key] = {}
self.tree_to_dict(cur_par, key)
I know this is wrong. It's why I need help.
The above code generates the following dict form the following QTreeWidget
a
b
a
c
{'a':'E', 'b':{'a':'E', 'c':'E'}}
But it should be:
{'a':'E', 'b':{'a':'E'}, 'c':'E'}
The E simply means that there will be no further subdirectories.
I've seen some other implementations of this but their horribly confusing and I don't quite get their logic. This is a near duplicate of the question I'm asking here, but it's yet to be answered. I've tried adapting his implementation but it's (to me anyway) convoluted and hard to fit into the structure of my program.
Your implementation is probably too complex than required.
Since each item is the key, you need to iterate recursively and return the values for that key.
If the item has no children, it will return 'E', otherwise will it will call the function again with the given child, and so on.
The function doesn't need the key argument, as it will be created by the recursive call.
def tree_to_dict(parent):
childCount = parent.childCount()
if not childCount:
return 'E'
content = {}
for row in range(childCount):
child = parent.child(row)
content[child.text(0)] = tree_to_dict(child)
return content
Then, just call the function using the invisibleRootItem().
I have a simple question about getting a key corresponding to a specific value in a dictionary in python. Please note I need only one command or one method(). No for loop, no writing def code, no map, or lambda etc., if there is a straightforward method() or command, please respond. If such a command does not exist in python, please create it and add it to the library. I suggest something like dic_inverse[value] or dic.inv(value) for the name of such a command.
Example: how to return the key corresponding to one specific value = 20 by one simple, clear, nice method() or command?
dict = {'age': 20, 'height' : 154}
dict_inverse[20] = ????
or dict.inverse(20) = ????
Creating and Looking up an inverse dict is as simple as it gets. You can abstract it into a function and pass in the dict and value to make your code cleaner.
def lookup_by_val(d, val)
inverse_dict = {v: k for k, v in d.items()}
return inverse_dict[val]
P.S. You might wanna add error handling if you are not sure that input is not safe.
I'm sure you are talking about Enum. Make sure that the values are always unique, otherwise it will only return the first key associated with that value.
Initializing Enum
First, you can initialize your Enum by setting up a class that inherits from the class Enum.
from enum import Enum
class Person(Enum):
age = 20
height = 154
Accessing Keys and Values
Then, you can get the corresponding value from a key.
>>> print(Person.age.value)
20
Or you can do it backward, getting the key from a value.
>>> print(Person(154).name)
height
My understanding is that .items() is only avaliable for python dictionaries.
However in the following bit of code, which runs perfectly, it appears that the .items() function is avaliable for a string. (This code is for the preprocessing stage of doc2vec )
I have looked at this for a while and I can't figure out why the .items() seems to work in this piece of code.
In the code, 'sources' is just an attribute of an instance. Yet it is able to call .items().
What am I missing here?
class LabeledLineSentence(object):
def __init__(self, sources):
self.sources = sources
flipped = {}
# make sure that keys are unique
for key, value in sources.items():
if value not in flipped:
flipped[value] = [key]
else:
raise Exception('Non-unique prefix encountered')
The given code only specifies that sources is an attribute of an instance. It doesn't specify its type. In fact it can be any type that is specified at the time of creating an instance of LabeledLineSentence.
i1 = LabeledLineSentence('sample text') # sources is now a string. Throws error!
i2 = LabeledLineSentence({}) # source is a now a dictionary. No error!
Note that LabeledLineSentence implementation expects the sources parameter to be a dictionary.
.items() is available for any class with an items method. For instance, I can define
class MyClass:
def items(self):
return [1,2,3,4]
and then run
mc = MyClass()
for i in mc.items(): print(i)
Presumably your sources object is of a class that has such an attribute. But we don't know what, since it's an argument to the constructor of LabeledLineSentence.
Can you point us to the full source code? Then we might be able to see what is being passed in.
I have a dictionary defined as
BREED_CLASS = {
'bdcl': ['Border Collie', BreedBdcl, 'BreedBdcl'],
}
and a model defined as
class Dog(models.Model):
breed_code = models.CharField(max_length=4, default='')
I'm trying to use the breed_code as a key to access the items in the dictionary, for example like this
return BREED_CLASS[instance.breed_code][0]
but that raises a KeyError, with exception value '' aka the default value.
I've tried doing something like
bc = instance.breed_code
and that correctly returns the value saved to that instantiated object ('bdcl'). But when I put that into the dictionary access as so
return BREED_CLASS[bc][0]
it gets me the same exact KeyError with the same exact exception value. How do I figure this out?
The CharField class seems to be using the __str__ magic method to return a string when you print it, giving you the illusion it is a string but it's actually an object. Your dictionary uses the actual string for storing the value but when you use BREED_CLASS[instance.breed_code] you are passing it the object. Converting your object to a string should fix it. Try this:
BREED_CLASS[str(instance.breed_code)][0]
So I figured out a workaround that gets me what I want, but I have no idea why it works.
This by itself does not work
return BREED_CLASS[instance.breed_code][2]
But having this for loop that iterates through the keys does
for key in BREED_CLASS:
if key == instance.breed_code:
return BREED_CLASS[instance.breed_code][2]
Notice that both return calls are identical, with instance.breed_code being used for the dict key index.
Does anyone have an answer as for why this is?
I need magic tool, that helps me to understand where one my problem variable is changed in the code.
I know about perfect tool:
pdb.set_trace()
and I need something similar format, but about only one variable changing history.
For example, my current problem is strange value of context['request'] variable inside Django's tag template definition method. The value is string '<<request>>' and I don't understand where it modified from Django's Request object. I can't debug it, because problem is appearing not so often, but permanently. I only see it in error emails and I can't call it specially. The perfect solution will be to create a log with variable's assignment and any modifications.
I'm not really familiar with django, so your mileage may vary. In general, you can override the __setitem__ method on objects to capture item assignment. However, this doesn't work on dictionaries, only on user-created classes, so first of all it depends on what this context object is.
As I get from a short look at the Django docs, it's indeed not a regular dict, so you can try something like this:
def log_setitem(obj):
class Logged(obj.__class__):
def __setitem__(self, item, val):
print "setting", item, "to", val, "on", self
super(Logged, self).__setitem__(item, val)
obj.__class__ = Logged
d = {}
try:
log_setitem(d) # throws an error
except:
print "doesn't work"
class Dict2(dict):
pass
d2 = Dict2()
log_setitem(d2) # this works
d2["hello"] = "world" # prints the log message before assigning
Even if this works, it of course only works if the assignment actually happens through the "standard" way, i.e. somewhere in the code there's a call like context['request'] = "something".
Might be worth a try, but I can't promise you anything.