How to change class object parameters from another module (python) - python

So I've searched around and couldn't find an answer. I'm looking to change parameters from an object created in my main file, in a module. For example, I'm testing this with a simple piece of code here:
-this is my main file, from which i create the objects and define some properties
import class_test_2
class dog():
name=''
spots=0
def add_spots(self):
self.spots+=1
def main():
fido=dog()
fido.name='Fido'
print('Fido\'s spots: ',fido.spots)
fido.add_spots()
print('Fido\'s spots: ',fido.spots)
class_test_2.class_test()
print('Fido\'s spots: ',fido.spots)
if __name__=='__main__':
main()
-this is the module, from which I want to use functions to change the attributes in the main file
from class_test_1 import dog
def class_test():
fido.add_spots()
-So my question is how can I do this/why doesn't this piece of code above work?
Running the main function on its own shows fido's spots increasing by 1 each time its printed. Running the code calling the module however gives a NameError so my module isn't recognising the class exists even though I've managed to import it. Thanks in advance for any help.

Your variable "fido" is only defined within your "main" function. You must provide your "class_test" function with the variable.
For example:
class_test_2.class_test(fido)
Then your class_test function gets an argument. You can choose the name freely. I used the_dog in the example:
def class_test(the_dog):
the_dog.add_spots()
In this case the_dog points to the same instance of your dog class as fido.

Related

Cannot call function from within imported function

I have 2 files, the first is named function_call_test.py and contains the following code;
from Strategy_File import strategy
def function_1():
print('This works')
strategy()
The second file is called Strategy_File.py and contains the following code;
def strategy():
print('got here')
function_1()
When running the first script I get 'NameError: name 'function_1' is not defined'.
I thought that when you imported a function that it was added to the importing modules namespace. If that is the case why can't strategy() see function_1()?
Just as importantly, how do I make this work. The above is for demo purposes only, I have reasons for wanting strategy() to be in a separate module.
Python 3.6, Windows 7-64, Visual Studio 2019 and IDLE
Python is statically scoped. Lookup for a free variable (such as function_1) proceeds though the scopes where strategy is defined, not where it is called. As strategy is defined in the global scope of the module Strategy_File, that means looking for Strategy_File.function_1, and that function is not defined.
If you want strategy to call something in the current global scope, you need to define it to accept a callable argument, and pass the desired function when you call strategy.
# Strategy_File.py
# f is not a free variable here; it's a local variable
# initialized when strategy is called.
def strategy(f):
print('got here')
f()
and
# function_call_test.py
from Strategy_File import strategy
def function_1():
print('This works')
# Assign f = function_1 in the body of strategy
strategy(function_1)
You have to import every name into the file where it is used. So you need to modify Strategy_File.py to this:
from function_call_test import function_1
def strategy():
print('got here')
function_1()
But now you encounter a new problem: circular imports. Python won't allow this. So you will have to figure out a different way to organize your functions.
This error caused by Strategy_File.py is missing definition of function_1().
adding this line in Strategy_File.py on the top will helps.
edit: circular imports will not help. sorry for the misinformation.

accessing and changing module level variable [duplicate]

I've run into a bit of a wall importing modules in a Python script. I'll do my best to describe the error, why I run into it, and why I'm tying this particular approach to solve my problem (which I will describe in a second):
Let's suppose I have a module in which I've defined some utility functions/classes, which refer to entities defined in the namespace into which this auxiliary module will be imported (let "a" be such an entity):
module1:
def f():
print a
And then I have the main program, where "a" is defined, into which I want to import those utilities:
import module1
a=3
module1.f()
Executing the program will trigger the following error:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.f()
File "Z:\Python\module1.py", line 3, in f
print a
NameError: global name 'a' is not defined
Similar questions have been asked in the past (two days ago, d'uh) and several solutions have been suggested, however I don't really think these fit my requirements. Here's my particular context:
I'm trying to make a Python program which connects to a MySQL database server and displays/modifies data with a GUI. For cleanliness sake, I've defined the bunch of auxiliary/utility MySQL-related functions in a separate file. However they all have a common variable, which I had originally defined inside the utilities module, and which is the cursor object from MySQLdb module.
I later realised that the cursor object (which is used to communicate with the db server) should be defined in the main module, so that both the main module and anything that is imported into it can access that object.
End result would be something like this:
utilities_module.py:
def utility_1(args):
code which references a variable named "cur"
def utility_n(args):
etcetera
And my main module:
program.py:
import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
And then, as soon as I try to call any of the utilities functions, it triggers the aforementioned "global name not defined" error.
A particular suggestion was to have a "from program import cur" statement in the utilities file, such as this:
utilities_module.py:
from program import cur
#rest of function definitions
program.py:
import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
But that's cyclic import or something like that and, bottom line, it crashes too. So my question is:
How in hell can I make the "cur" object, defined in the main module, visible to those auxiliary functions which are imported into it?
Thanks for your time and my deepest apologies if the solution has been posted elsewhere. I just can't find the answer myself and I've got no more tricks in my book.
Globals in Python are global to a module, not across all modules. (Many people are confused by this, because in, say, C, a global is the same across all implementation files unless you explicitly make it static.)
There are different ways to solve this, depending on your actual use case.
Before even going down this path, ask yourself whether this really needs to be global. Maybe you really want a class, with f as an instance method, rather than just a free function? Then you could do something like this:
import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()
If you really do want a global, but it's just there to be used by module1, set it in that module.
import module1
module1.a=3
module1.f()
On the other hand, if a is shared by a whole lot of modules, put it somewhere else, and have everyone import it:
import shared_stuff
import module1
shared_stuff.a = 3
module1.f()
… and, in module1.py:
import shared_stuff
def f():
print shared_stuff.a
Don't use a from import unless the variable is intended to be a constant. from shared_stuff import a would create a new a variable initialized to whatever shared_stuff.a referred to at the time of the import, and this new a variable would not be affected by assignments to shared_stuff.a.
Or, in the rare case that you really do need it to be truly global everywhere, like a builtin, add it to the builtin module. The exact details differ between Python 2.x and 3.x. In 3.x, it works like this:
import builtins
import module1
builtins.a = 3
module1.f()
As a workaround, you could consider setting environment variables in the outer layer, like this.
main.py:
import os
os.environ['MYVAL'] = str(myintvariable)
mymodule.py:
import os
myval = None
if 'MYVAL' in os.environ:
myval = os.environ['MYVAL']
As an extra precaution, handle the case when MYVAL is not defined inside the module.
This post is just an observation for Python behaviour I encountered. Maybe the advices you read above don't work for you if you made the same thing I did below.
Namely, I have a module which contains global/shared variables (as suggested above):
#sharedstuff.py
globaltimes_randomnode=[]
globalist_randomnode=[]
Then I had the main module which imports the shared stuff with:
import sharedstuff as shared
and some other modules that actually populated these arrays. These are called by the main module. When exiting these other modules I can clearly see that the arrays are populated. But when reading them back in the main module, they were empty. This was rather strange for me (well, I am new to Python). However, when I change the way I import the sharedstuff.py in the main module to:
from globals import *
it worked (the arrays were populated).
Just sayin'
A function uses the globals of the module it's defined in. Instead of setting a = 3, for example, you should be setting module1.a = 3. So, if you want cur available as a global in utilities_module, set utilities_module.cur.
A better solution: don't use globals. Pass the variables you need into the functions that need it, or create a class to bundle all the data together, and pass it when initializing the instance.
The easiest solution to this particular problem would have been to add another function within the module that would have stored the cursor in a variable global to the module. Then all the other functions could use it as well.
module1:
cursor = None
def setCursor(cur):
global cursor
cursor = cur
def method(some, args):
global cursor
do_stuff(cursor, some, args)
main program:
import module1
cursor = get_a_cursor()
module1.setCursor(cursor)
module1.method()
Since globals are module specific, you can add the following function to all imported modules, and then use it to:
Add singular variables (in dictionary format) as globals for those
Transfer your main module globals to it
.
addglobals = lambda x: globals().update(x)
Then all you need to pass on current globals is:
import module
module.addglobals(globals())
Since I haven't seen it in the answers above, I thought I would add my simple workaround, which is just to add a global_dict argument to the function requiring the calling module's globals, and then pass the dict into the function when calling; e.g:
# external_module
def imported_function(global_dict=None):
print(global_dict["a"])
# calling_module
a = 12
from external_module import imported_function
imported_function(global_dict=globals())
>>> 12
The OOP way of doing this would be to make your module a class instead of a set of unbound methods. Then you could use __init__ or a setter method to set the variables from the caller for use in the module methods.
Update
To test the theory, I created a module and put it on pypi. It all worked perfectly.
pip install superglobals
Short answer
This works fine in Python 2 or 3:
import inspect
def superglobals():
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals
save as superglobals.py and employ in another module thusly:
from superglobals import *
superglobals()['var'] = value
Extended Answer
You can add some extra functions to make things more attractive.
def superglobals():
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals
def getglobal(key, default=None):
"""
getglobal(key[, default]) -> value
Return the value for key if key is in the global dictionary, else default.
"""
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals.get(key, default)
def setglobal(key, value):
_globals = superglobals()
_globals[key] = value
def defaultglobal(key, value):
"""
defaultglobal(key, value)
Set the value of global variable `key` if it is not otherwise st
"""
_globals = superglobals()
if key not in _globals:
_globals[key] = value
Then use thusly:
from superglobals import *
setglobal('test', 123)
defaultglobal('test', 456)
assert(getglobal('test') == 123)
Justification
The "python purity league" answers that litter this question are perfectly correct, but in some environments (such as IDAPython) which is basically single threaded with a large globally instantiated API, it just doesn't matter as much.
It's still bad form and a bad practice to encourage, but sometimes it's just easier. Especially when the code you are writing isn't going to have a very long life.

Passing variables between two files both ways in python

Okay, so I know this may seem stupid but I am currently making a game using multiple files, one main one that receives all variables from other files and uses them in ways. I'm using the:
from SPRITES import *
to get these variable over, however now I need a variable that can only be defined in MAIN in SPRITES (as the platform the player is standing on is located in main, and this needs to change the controls defined in sprites), however if I just do a
from MAIN import *
this seems to break the connection completely. Help please
EDIT: Okay, currently my file is probs too large to post all code on here but I'll try to post whats relevent on here (first time here). This is the start to the main 'titleMAIN' file
import pygame as pg
import random
from titleSETTING import *
from titleSPRITE import *
cont = ("green")
class Game:
def __init__(self):
# initialize game window, etc
pg.init()
and so on
calling upon the Player class in the SPRITES file from the Game class - I need to be able to use the 'cont' variable in the Player class:
def new(self):
# start a new game
cont = ("green")
...
self.player = Player(self)
self.all_sprites.add(self.player)
And here is where I tried to call upon the MAIN file from the SPRITES file:
from titleSETTING import *
...
class Player(pg.sprite.Sprite):
def __init__(self, game):
Sorry that I was vague, first time here and kinda a novice at coding, no matter how much I enjoy it. BTW by files I mean different python (.py) files in the same folder - using IDLE as an IDE, which sucks but it's what I got
EDIT 2: Thanks for the responses - I realize that it's probably better to just try to make this all one file instead of two, so to not over complicate the code, so I'll work with that mindset now
The main reason this wasn't working for you is that circular imports are problematic. If some file A imports some other file B, then you do not want B to import A (even indirectly, via some other files).
So to make it work, I split main into two.
As an aside, using global variables (and import *) tends to make programs harder to read. Instead of a bunch of globals, consider perhaps a single global that has the values you need as fields. Instead of import *, consider explicit imports (just import sprites, and then sprites.foo).
main.py:
from sprites import *
from config import *
print "Hello from main. main_value is: ", main_value
print "sprite value is: ", sprite_value
do_sprite()
sprites.py:
from config import *
sprite_value=10
def do_sprite():
print "main value is: ", main_value
config.py:
main_value=5
While technically possible (using some obscure Python features), what you're trying to achieve is neither easy, nor actually a good idea.
Note that the fact that you did from moduleX import *, doesn't make the variables defined in moduleX magically available in main (or where-ever you put the import statement). What it does, it creates new variables with the same names in your current module and make them point to the same objects as those in moduleX at the moment when the import is executed. Let's say there's A in some module named X and it was initialized to "foo". You did import * from X and now print(A) will show foo. If you now call a function from X and it changes A to bar, it won't affect what you have in main - that is still the object foo. Likewise, if you do a="baz" in main, functions from X that refer to A will still see X's copy of that variable.
If you need some data to be available to more than one module, it may be best to arrange for all that shared data to be stored in some common object and have an easily-accessible reference to that object in all the modules that need the shared data. Here are possible choices for this object, pick what suits your taste:
it can be a module that's just meant to keep common variables, let's say it is called data or common (have an empty file data.py). Import it everywhere you need to and set variables as data.A = "something" or use them as needed, e.g. print (data.A).
it can be an instance of a class that you define yourself,
e.g.:
class data_class(object):
# set initial values
var1 = 10
A = "foo"
Now, create an instance of it with data = data_class() and pass it to every module that needs it. E.g., define it in one module and import it from everywhere else.
you can also use a Python dictionary (and, like with the class instance, have a reference to it in all modules). You will then refer to your common data items as data["A"], etc.

Python my Class throws TypeError

here is my code.
import fileinput, random
from os import system as sys
from sys import exit
class crazy8(object):
question = raw_input("please enter a yes or no question \n")
def fortune(self, filex, current):
current = r"./"
fortunes = list(fileinput.input(filex))
sys("cd", current)
print random.choice(fortunes)
crazy8.fortune(r"./crazy8")
exit(0)
When I run the program, I enter a question (I know that the program does not care what is entered). I think I did something wrong with the class. I know it works fine when there is no class: statement, but I need the class there (after I am done, I am going to use this as a module).
After the question, I get
TypeError: unbound method fortune() must be called with crazy8 instance as first argument (got str instance instead)
(I did not add any error checking yet. I will try to add try and catch/raise for if the file ./crazy8 does not exist. Also, I am later going to add a file that will automatically sys("touch ./crazy8") (on Mac/linux) and, after I find out how to create a file on Windows, I will add that.
You need to create and instance or object of the class(same thing).
x = crazy8()
x.fortuner(r,"./crazy8")
It's also considered common practice to have your classes start with capital letters and instances with lowercase.
class Crazy8
crazy8 = Crazy8()
Hope this helps
Either you should create an instance of the class and call its method, or you should make the method static.
Please refer to:
Static methods in Python

Python: Calling module's functions from within a class

I have the following code:
from suchandsuch import bot
class LaLaLa():
def __init__(self):
self.donenow = 0
print "LaLaLa() initialized."
return
def start(self):
pages = bot.cats_recursive('something')
for page in pages:
self.process_page(page)
When I try to run y = LaLaLa() and then y.start(), though, I get an error:
AttributeError: LaLaLa instance has no attribute 'cats_recursive'
This makes me suspect that Python is trying to call cats_recursive() not from suchandsuch's bot sub-module (as is defined at the beginning of the file), but rather from LaLaLa(), which of course doesn't have the cats_recursive() function. Is there a way to force a class instance to use an imported module, rather than just look inside itself?
Posters are correct that there is nothing wrong with the code you have posted.
It's the code you didn't post that is probably the problem. It is hinted at in your naming of cats_recursive. You haven't shown us that perhaps LaLaLa is defined in or imported into bot.py.
One way to replicate your error is:
# in suchandsuch/bot.py
class LaLaLa():
def __init__(self):
self.donenow = 0
print "LaLaLa() initialized."
# don't need a `return` here
def start(self):
pages = bot.cats_recursive('something')
for page in pages:
self.process_page(page)
bot = LaLaLa()
That's just one. Another is to have __init__.py in such and such something like:
bot = LaLaLa()
Like I said, the error is in your code structure.
print the id of the bot inside LaLaLa or captrue the error with pydb and I suspect you will see that bot is an instance of LaLaLa other than y (again check the id's)
You are doing fine. Most probably there is no cats_recursive() attribute in your module for real. Check syntax, check module content.
You might find the easiest way to do this would be to try to assign the cats_recursive() to the pages variable outside the class and then pass the variable to the start() function as a parameter. If this works then keep it that way, if it doesn't work then there's probably something wrong with the code elsewhere.

Categories