mgolunski
mgolunski

Reputation: 45

Change object's variable from different file

I want to access object (specifically its variables) from functions defined in different file. Let's see an example:

File 1 - grail.py

import enemies

class Encounter:
    def __init__(self):
        self.counter = 1
        self.number = 0
        self.who = "We've encountered no one."

    def forward(self):
        if self.counter == 1:
            enemies.knightofni()
        elif self.counter == 2:
            enemies.frenchman()
        else:
            self.number = 42
            self.who = "We've found the Grail!"
        self.counter += 1

knight = Encounter()
for i in range(4):
    print(str(knight.number) + " " + knight.who)
    knight.forward()

File 2 - enemies.py (I probably need something in this file)

def knightofni():
    Object.number = 1
    Object.who = "We've encountered Knight of Ni."

def frenchman():
    Object.number = 4
    Object.who = "We've encountered French."

Output should show:

0 We've encountered no one.
1 We've encountered Knight of Ni.
4 We've encountered French.
42 We've found the Grail!

I know you can achieve the output by returning something from functions in file enemies.py, for example function frenchman() could look like:

def frenchman():
    return [4, "We've encountered French."]

and in grail.py I should change code to collect what the frenchman() returns:

...
        elif self.counter == 2:
            spam = enemies.frenchman()
            self.number = spam[0]
            self.who = spam[1]
...

but it uses additional resources, makes the code longer, and more cumbersome in more complicated situations.

Is there a way to do the job directly on the object's variables but keeping functions in separate file?

EDIT There are already answers to this question but maybe I will add clarification seeing doubt in one of the answers (citing comment to this answer):

I want it to be possible to add other "enemies" without making lengthy code in this place (so forward() is kind of a wrapper, place where it is decided what to do in different situations). It is also more readable if this functions are in different file.

Think of situation where there would be 100 "enemies" and each would need to change 100 variables which are lists with 1M entries each. Is there a better way than putting "enemies" into other file and changing variables directly in the file?

Upvotes: 1

Views: 89

Answers (2)

Mike Müller
Mike Müller

Reputation: 85432

Problem

You need to hand over the object as argument.

In the function:

def knightofni(obj):
    obj.number = 1
    obj.who = "We've encountered Knight of Ni."

and when using it in the class:

enemies.knightofni(self)

Do the same for frenchman().

Full code

grail.py

import enemies

class Encounter:
    def __init__(self):
        self.counter = 1
        self.number = 0
        self.who = "We've encountered no one."

    def forward(self):
        if self.counter == 1:
            enemies.knightofni(self)
        elif self.counter == 2:
            enemies.frenchman(self)
        else:
            self.number = 42
            self.who = "We've found the Grail!"
        self.counter += 1

knight = Encounter()
for i in range(4):
    print(str(knight.number) + " " + knight.who)
    knight.forward()

and enemies.py:

def knightofni(obj):
    obj.number = 1
    obj.who = "We've encountered Knight of Ni."

def frenchman(obj):
    obj.number = 4
    obj.who = "We've encountered French."

Output:

0 We've encountered no one.
1 We've encountered Knight of Ni.
4 We've encountered French.
42 We've found the Grail!

Upvotes: 2

mr2ert
mr2ert

Reputation: 5186

It is possible to do this, though I don't know why you would really want to do it this way.

In your forward and __init__ methods you'll notice that you are passing in self, which is the instance of Encounter you are operating on. That is why you can do self.number = 42 and get the correct number when you call knight.number.

Since self is just an object you can pass it into the functions in 'enemies.py'.

Try:

# grail.py
def forward(self):
    if self.counter == 1:
        enemies.knightofni(self)
    elif self.counter == 2:
        enemies.frenchman(self)
    else:
        self.number = 42
        self.who = "We've found the Grail!"
    self.counter += 1

#enemies.py
def knightofni(that):
    that.number = 1
    that.who = "We've encountered Knight of Ni."

def frenchman(that):
    that.number = 4
    that.who = "We've encountered French."

Upvotes: 0

Related Questions