質問

I have a dictionary-like object which store descriptors inside:

 class MyDict(object):
    def __init__(self):
        dict.__init__(self)

    def __getitem__(self, key):
        v = dict.__getitem__(self, key)
        if hasattr(v, '__get__'):
           return v.__get__(None, self)
        return v

class MyDescriptor(object):
    def __init__(self, value, attrib={}):
        self.__value = value
        self.attrib= attrib

    def __get__(self, instance, owner):
        return self.__value

    def __set__(self, instance, value):
        self.__value = value

I want to be able to do the following:

d = MyDict()
d['1'] = MyDescriptor("123", {"name": "val"})
print d['1']                     # prints "123"
print d['1'].attrib["name"]      # prints "val"

My classes don't work. Could you please help me?

役に立ちましたか?

解決

Your solution looks unnecessarily complicated to solve your problem, unless there's more to it that is shown. Why not simply do this:

class MyObject(object):
    def __init__(value, attrib=None):
        self.__value = value
        self.attrib = {} if attrib is None else attrib

    def __str__(self):
        return __value

d = {}
d['1'] = MyObject("123", {"name": "val"})
print d['1']                     # prints "123"
print d['1'].attrib["name"]      # prints "val"

As for why your code doesn't work, there are a few obvious problems.

  • From your calls in various special methods of __dict__, it appears that MyDict is meant to subclass dict, so the definition should be:

    class MyDict(dict):
        ...
    
  • While not incorrect, it is better practice to use super rather than referring to the base class directly, so dict.__init__(self) would become super(MyDict, self).__init__() and dict.__getitem__(self, key) becomes super(MyDict, dict).__getitem__(key).

  • Your call to get sill work, but doesn't match the method specification. You should call it as v.__get__(self, MyDict). However, the way you are using it actually makes __get__ redundant, and I think that this usage it where the main problem lies.

  • In class MyDescriptor, early binding will give you unexpected results for attrib. See my example above for a better way for declaring it.

I suspect that instead of a description, what you actually want is an object which looks like a string (for some definition of "looks like"), but has an attribute attrib. To do this, there is no need to try to create a descriptor, which is intended for a different use case altogether. My example above gives a class which satisfies the requirement of an object which "looks like" a string, where "looks like" means it prints a string, but here is another which may be more like what you want:

class MyString(str):
    def __init__(self, value, attrib=None):
        super(MyString, self).__init__(value)
        self.attrib = {} if attrib is None else attrib

他のヒント

I'm not sure if this solves your use case, but in terms of achieving the results you've stated you could simply remove your MyDict class and use an ordinary dict:

d = {}

Then, add a __str__ method to the MyDescriptor class returning self.__value and you'll achieve the results you've described.

>>> d['1'] = MyDescriptor("123", {"name": "val"})
>>> d['1']                     
123
>>> d['1'].attrib["name"] 
val
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top