搜索历史
热搜词
监控Tomcat解决方案(监控应用服务器系列文章)

推荐:监控应用服务器---使用JMX监控Tomcat

[前言:做了一个监控应用服务器的项目(支持Tocmat、WebSphere、WebLogic各版本), 过程也算是磕磕绊绊,由于网上缺少相关资料,或者深陷于知识的海洋难以寻觅到有效的资

up vote 0 down vote favorite

This question already has an answer here:

Is it possible to create a variable name based on the value of a string?

I have a script that will read a file for blocks of information and store them in a dictionary. Each block's dictionary will then be appended to a 'master' dictionary. The number of blocks of information in a file will vary and uses the word 'done' to indicate the end of a block.

I want to do something like this:

master={}
block=0
for lines in file:
  if line != "done":
    $block.append(line)
  elif line == "done":
    master['$block'].append($block)
    block = block + 1

If a file had content like so:

eggs
done
bacon
done
ham
cheese
done

The result would be a dictionary with 3 lists:

master = {'0': ["eggs"], '1': ["bacon"], '2': ["ham", "cheese"]}

How could this be accomplished?

python list variables dictionary naming share | improve this question edited Jun 20 '12 at 18:54 Gareth Latty 51.3k 8 97 135 asked Jun 20 '12 at 18:52 Rauffle 172 2 3 12

marked as duplicate by Marcin python Users with the  python badge can single-handedly close python questions as duplicates and reopen them as needed. Aug 15 '14 at 16:59

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

     Made your dictionary actually a python dict. –  Gareth Latty Jun 20 '12 at 18:55      It doesn't seem to me like you need a dictionary, since you're indexing your dictionary items sequentially using integers which start at 0. Use a list of lists instead. –  machine yearning Jun 20 '12 at 19:03      Perhaps I shouldn't have included the example, but I'm still wondering if there's a way to name a variable based on a string's value (and not just a dictionary key) –  Rauffle Jun 21 '12 at 22:14 add a comment  | 

5 Answers 5

active oldest votes up vote 3 down vote accepted

I would actually suggest you to use a list instead. Is there any specific point why would you need dicts that are array-ish?

In case you could do with an array, you can use this:

with open("yourFile") as fd:
    arr = [x.strip().split() for x in fd.read().split("done")][:-1]

Output:

推荐:使用JMX监控Tomcat(监控应用服务器系列文章)

[ 前言:做了一个监控应用服务器的项目(支持Tocmat、WebSphere、WebLogic各版本), 过程也算是磕磕绊绊,由于网上缺少相关资料,或者深陷于知识的海洋难以寻觅到有效的

[['eggs'], ['bacon'], ['ham', 'cheese']]

In case you wanted number-string indices, you could use this:

with open("yourFile") as fd:
    l = [x.strip().split() for x in fd.read().split("done")][:-1]
    print dict(zip(map(str,range(len(l))),l))
share | improve this answer edited Jun 21 '12 at 12:46 answered Jun 20 '12 at 18:57 SuperSaiyan 24.8k 6 49 79      @Downvoters: Can you please explain the action? –  SuperSaiyan Jun 20 '12 at 19:02      Why did someone downvote this? It seems to me more correct than the other answers, since it not only answers the question, but it provides a more elegant data structure than the OP intended. –  machine yearning Jun 20 '12 at 19:02 1   @FrancisW.Usher: Yes, I understand. But is there any harm in suggesting a more readable, concise, and a pythonic way of doing things? –  SuperSaiyan Jun 20 '12 at 19:09 1   As written, the list comprehension leaks a file ref, unfortunately. (Side note: I think calling str on the returns from itertools.count would be much cleaner than getNextNumber.) –  DSM Jun 20 '12 at 19:10 1   @Friends: I didn't mean to suggest that you don't include your list comprehension and mention that it's the right way of doing things. However since this syntax is not generally familiar or intuitive for beginning programmers, I usually additionally provide the analogous for loop version, for beginners' reference. –  machine yearning Jun 20 '12 at 19:11  |  show 6 more comments up vote 2 down vote

You seem to be misunderstanding how dictionaries work. They take keys that are objects, so no magic is needed here.

We can however, make your code nicer by using a collections.defaultdict to make the sublists as required.

from collections import defaultdict

master = defaultdict(list)
block = 0
for line in file:
    if line == "done":
        block += 1
    else:
        master[block].append(line)

I would, however, suggest that a dictionary is unnecessary if you want continuous, numbered indices - that's what lists are for. In that case, I suggest you follow Thrustmaster's first suggestion, or, as an alternative:

from itertools import takewhile

def repeat_while(predicate, action):
    while True:
        current = action()
        if not predicate(current):
            break
        else:
            yield current

with open("test") as file:
    action = lambda: list(takewhile(lambda line: not line == "done", (line.strip() for line in file)))
    print(list(repeat_while(lambda x: x, action)))
share | improve this answer edited Jun 20 '12 at 19:14 answered Jun 20 '12 at 18:57 Gareth Latty 51.3k 8 97 135 add a comment  |  up vote 1 down vote

I think that split on "done" is doomed to failure. Consider the list:

eggs
done
bacon
done
rare steak
well done stake
done

Stealing from Thrustmaster (which I gave a +1 for my theft) I'd suggest:

>>> dict(enumerate(l.split() for l in open(file).read().split('\ndone\n') if l))
{0: ['eggs'], 1: ['bacon'], 2: ['ham', 'cheese']}

I know this expects a trailing "\n". If there is a question there you could use "open(file).read()+'\n'" or even "+'\n\ndone\n'" if the final done is optional.

share | improve this answer answered Jun 20 '12 at 19:55 Phil Cooper 3,865 13 30 add a comment  |  up vote 0 down vote

Use setattr or globals().
See How do I call setattr() on the current module?

share | improve this answer answered Jun 20 '12 at 18:56 Thomas Orozco 27.5k 4 47 76      Read the question, this isn't actually what he is asking –  Gareth Latty Jun 20 '12 at 18:57      Indeed, and if it so, your answer is the right one, so I'll leave that one here and upvote yours. –  Thomas Orozco Jun 20 '12 at 18:59 add a comment  |  up vote 0 down vote

Here's your code again, for juxtaposition:

master={}
block=0
for lines in file:
  if line != "done":
    $block.append(line)
  elif line == "done":
    master['$block'].append($block)
    block = block + 1

As mentioned in the post by Thrustmaster, it makes more sense to use a nested list here. Here's how you would do that; I've changed as little as possible structurally from your original code:

master=[[]] # Start with a list containing only a single list
for line in file: # Note the typo in your code: you wrote "for lines in file"
  if line != "done":
    master[-1].append(line) # Index -1 is the last element of your list
  else: # Since it's not not "done", it must in fact be "done"
    master.append([])

The only thing here is that you'll end up with one extra list at the end of your master list, so you should add a line to delete the last, empty sublist:

del master[-1]
share | improve this answer answered Jun 20 '12 at 19:30 machine yearning 4,923 2 18 49 add a comment  | 

Not the answer you're looking for? Browse other questions tagged python list variables dictionary naming or ask your own question.

主题:

分享:

相 关 推 荐

热 门 推 荐