开发者

How do you make an access a hash in python?

I know this question sounds very basic. But I can't find it using Google. I know that there are dictionaries that look like

o = {
  'a': 'b'
}

and they're accessed with o['a']. But what are the ones that are accessed as o.a called? I know they exist because I'm using optp开发者_如何学编程arse library and it returns an object accessible like that.


You can not access dicts using the '.' unless you implement your own dict type by deriving from dict and providing access through the '.' notation by implementing the __getattribute__() API which is in charge for performing attribute style access.

See http://docs.python.org/reference/datamodel.html#object.__getattribute__


Looks to me like optparse simulates an attribute interface to a hidden dict, but there's a standard library that does something sort of similar, if not really a dictionary: collections.namedtuple. I can't speak to the other mechanisms presented here.


You can access the variables as a dictionary in "new style classes". I think you have to be a little careful though.

>>> class C(object): # python 2 code, inheriting from 'object' is automatic in 3
    a = 5
    def __init__(self):
        self.j = 90


>>> c = C()
>>> c.__dict__
{'j': 90}
>>> print c.j
90
>>> print c.a
5

notice that 'j' showed up in the dictionary and 'a' didn't. It looks to have something to do with how they are initialized. I'm a little confused by that behavior and wouldn't mind an explanation from a guru :D

Edit:

Doing a little more playing, it is apparent why they decided to go with the behavior above (but it is still a little strange

>>> class C(object):
    a = 5
    def __init__(self):
        self.j = 90
        self.funct = range # assigning a variable to a function

>>> c = C()
>>> c.__dict__
{'j': 90, 'funct': <built-in function range>}

I think it separates the class object (which would be the same for every class) with new class members (such as those initiated inside init). If I now do

>>> c.newvar = 234
>>> c.__dict__
{'j': 90, 'newvar': 234, 'funct': <built-in function range>}

You can see it is building a dictionary! Hopefully this helps :D


name.attribute is object access in Python, not dict access


__getattr__ is the method you want to implement, along with __setattr__. Here is a very simplistic example (no error checking, etc) that shows an object which allows both dictionary-style and attribute-style access:

Missing = object()

class AttrElem(object):
    def __init__(self, **kwds):
        self.items = kwds.copy()
    def __getitem__(self, name):
        result = self.items.get(name, Missing)
        if result is not Missing:
            return result
        raise KeyError("key %r not found" % name)
    def __setitem__(self, name, value):
        self.items[name] = value
    def __getattr__(self, name):
        result = self.items.get(name, Missing)
        if result is not Missing:
            return result
        raise AttributeError("attribute %r not found" % name)
    def __setattr__(self, name, value):
        if name == 'items':
            object.__setattr__(self, name, value)
        else:
            self.items[name] = value
    def __repr__(self):
        return 'AttrElem(%s)' % ', '.join(
                ["%s:%s" % (k, v) for k, v in self.items.items()]
                )

In use it looks like this:

example = AttrElem(this=7, that=9)
print(example)
example.those = 'these'
example['who'] = 'Guido'
print(example)

As you can see from the code __getitem__ and __getattr__ are both very similary, differing only in the exception that gets raised when the target cannot be found.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜