NDevox
NDevox

Reputation: 4086

accessing a variable reference with a list

I'm making a civclicker type game in python, which requires me to kill off workers when the food variable becomes negative.

Currently the method I'm thinking of using for this is using random.choice on a list, and I'm wondering if I could make the list hold a reference to a variable.

Here is my function:

self.maxPopulation = 0
self.workers = 0
self.farmers = 0
self.miners = 0
self.loggers = 0

def random_killer(self, amount):
    for i in range(round(amount)):
        choice = []
        choice += [self.farmers] * self.farmers + [self.miners] * self.miners + [self.loggers] * self.loggers + [self.workers] * self.workers
        chosen = random.choice(choice)
        chosen -= amount

So this is obviously not working as the resultant choice list is just an array of numbers. I've also made self.farmers etc. text strings and used the exec function (which didn't work), but I'm aware that using exec/eval is bad practice.

Another consideration is moving everything into a dictionary, but that will require a more general overhaul of the code - which I'm leaving for when a few other basic systems are in place.

Disregarding that - I'm curious as to whether you can actually store the reference to the self.farmers etc. variables in a list, as opposed to passing in numbers.

so my question is: Can you store the reference or pointer to a variable, e.g.self.farmers, within a list, so that the reference can be passed to another variable, chosen, allowing me to edit self.farmers dynamically.

Edit:

added a bit more detail. self.farmers/miners/loggers/workers is a reference to the number of people in each category.

The function above is supposed to create a list which is made by taking a reference to the above variables, and then multiplying the number of references to a variable by the number that variable represents. So in a sense if we had 5 farmers we would get a list which looks like [self.farmers, self.farmers, self.farmers, self.farmers, self.farmers].

In an artificial sense each item in a list represents a person in the game, and when they are selected, that person is killed. Realistically it's just a number of references to the same variable, which is then decreased by an arbitrary amount on selection.

Upvotes: 0

Views: 54

Answers (1)

jonrsharpe
jonrsharpe

Reputation: 122154

This would probably be easier with a dictionary. I will demonstrate it outside a class for brevity, but it could easily be an instance attribute (and you could expose the values as attributes via properties or __getattr__):

>>> import random
>>> people = {'miners': 1,
              'workers': 2,
              'farmers': 3,
              'loggers': 4}
>>> choices = [k for k, v in people.items() for _ in range(v)]
>>> choices
['loggers', 'loggers', 'loggers', 'loggers', 'workers', 'workers', 'miners', 'farmers', 'farmers', 'farmers']
>>> occupation = random.choice(choices)
>>> occupation
'loggers'
>>> people[occupation] -= 1
>>> people
{'loggers': 3, 'workers': 2, 'miners': 1, 'farmers': 3}

Note that you probably want to subtract 1 within your for loop, not amount.


To do this purely with attributes, use getattr and setattr, and store the attribute names in choices:

class Population(object):

    OCCUPATIONS = ('miners', 'workers', 'farmers', 'loggers')

    def __init__(self):
        self.miners = 1
        self.workers = 2
        self.farmers = 3
        self.loggers = 4

    def kill_random(self, n):
        for _ in range(n):
            choices = [attr for attr in self.OCCUPATIONS
                       for _ in range(getattr(self, attr))]
            occupation = random.choice(choices)
            setattr(self, occupation, getattr(self, occupation)-1)

In use:

>>> a = Population()
>>> a.kill_random(3)
>>> a.miners
0
>>> a.workers
2
>>> a.farmers
1
>>> a.loggers
4

Upvotes: 1

Related Questions