質問

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.

  1. 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.

  2. 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.

  3. replace the list comprehension with a generator expression list(field + "_value" for field in _unique_fields) which does not share this problem

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top