You can create two .csv files, one for the 20 animal words, and one for 40 non-animal words. They would look like this:
word type
cat animal
dog animal
gnu animal
etc
word type
rock non-animal
stick non-animal
leaf non-animal
etc
Read each one in with a DictReader: https://docs.python.org/3/library/csv.html#csv.DictReader
This imports the file into a list of dictionaries, where each dictionary contains both the name and its associated type, e.g. the list would look like this:
[{'word':'cat', 'type':'animal'}, {'word':'dog', 'type':'animal'}, etc]
So lets say you have two lists, one called animals and one called non_animals, then just go through the same sort of list manipulation as before:
# randomise words across trials and blocks:
shuffle(animals)
shuffle(non_animals)
A_words = animals[0:10] + non_animals[0:20]
shuffle(A_words) # randomise across types, within block
B_words = animals[10:20] + non_animals[20:40]
shuffle(B_words) # randomise across types, within block
all_words = A_words + B_words # optional?
So now to use the word, e.g. in a text stimulus, you need to extract it from the dictionary for this trial, e.g:
trial_details = all_words.pop() # the values for this trial
current_word = trial_details['word']
current_type = trial_details['type']
your_loop_name.addData('word', current_word) # record in the data file
your_loop_name.addData('type', current_type)