2

I have a container class for urls and their headers, Resource:

class Resource(object):
    def __init__(self, url, headers):
        self.url = url
        self.content-length = headers['content-length']
        self.content-type = headers['content-type']

        # etc....

The headers argument to the __init__ method expects a dict returned from the getinfo() method of urllib2.urlopen(). I thought this would be a more readable way of packaging up the resource url and headers. Typing self.someheader = headers['someheader'] over and over made me wonder if there's some way to automate creating variables from dictionary keys like this. Is this possible?

3
  • 4
    That is not valid Python! If you realize that, you also realize why it's impossible to do this for general dicts. Commented Apr 6, 2012 at 11:08
  • This is sort of dangerous. Like PHP automatic variables. Commented Apr 6, 2012 at 11:08
  • 1
    @PabloSantaCruz what makes it dangerous? Does it create some kind of security issue? Commented Apr 6, 2012 at 11:16

2 Answers 2

4

Python identifiers can't have the - symbol in them! So we can replace it with _ in the keys.
Changing the keys to lowercase makes them look like a conventional variable name, and, what is very important, removes uppercase/lowercase confusion (because headers are usually sent with capitalized keys).

for k, v in headers.items():
    setattr(self, k.lower().replace('-', '_'), v)

If you're using Python 2, iteritems is better here, as it doesn't create a new list of items, but just lets you iterate over them, which Python 3 does by default.

It may be a good idea to store those keys in a "private" dict (e. g. self._headers). Then you can have much more control over the process with __getattr__ and __setattr__, for example, an exception can be raised during an attempt to set an invalid key.

Sign up to request clarification or add additional context in comments.

2 Comments

@NiklasB.: Yes. Well, you could remove the comment now... I edited the answer before your comment anyway.
Thanks heaps for the referral to __getattr__ and __setattr__, that's a much better way of doing what I want to do
1

Consider using a class such as the following

class ADict(dict):
    def __getattr__(self, field):
        return self.get(field)

which would then allow you to simply wrap your header in it. This would, as other people have pointed out - still not allow you to access the attributes with that include a dash, however you could use getattr instaed to access these attributes. Consider the following header, wrapped in ADict:

header = {'content-type': 'text/javascript', 'content-length': 30, 'accept': 'text/html'}
aheader = ADict(header)

Attributes such as accept can be accessed using the familiar dot-syntax whereas invalid identifier attributes can be accessed through getattr

>>>> aheader.accept
'text/html'
>>>> getattr(aheader, 'content-length')
30

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.