Set/Modify the variable used in a function from imported module - python-3.x

Consider following code:
##testing.py
namespace = "original"
def print_namespace():
print ("Namespace is", namespace)
def get_namespace_length(_str = namespace):
print(len(_str))
##Main
import testing
testing.namespace = "test"
testing.printnamespace()
testing.get_namespace_length()
print_namespace() return 'test' as exepcted, but the get_namespace_length() still return 8 which is the length of 'original'. How can I make get_namespace_length() taking the modified variable?
The use case of such implementation is some functions are used the same variable in the imported module, if I can modify/set variable, I can avoid explicitly to call out new variable in each function. Can someone advise?
Also, it doesn't have to be implemented in the way shown above, as long as it works. (global variable etc.)

Um... your default argument for get_namespace_length is database, undefined in your code snippet, also you switch from calling testing to test (I'm guessing that was one of many typos).
In short though, I believe its to do with how the bytecode is compiled in python. Arguments are 'preloaded', and therefore a change to a variable (such as namespace) does not get included in the compilation of get_namespace_length. If I remember correctly, upon import the entire code of the imported file is compiled and executed (try putting a print() statement at the end of testing.py to see)
So what you really want to do to obtain your length of 4 is change testing.py to:
namespace = "original"
def print_namespace():
print ("Namespace is", namespace)
def get_namespace_length():
_str = namespace
print(len(_str))
Or just print(len(namespace)).
Hope that helps!

Related

exec() not working when trying to execute a string containing the command "abs.__doc__"

I am trying to execute the command abs.__ doc__ inside the exec() function but for some reason it does not work.
function = input("Please enter the name of a function: ")
proper_string = str(function) + "." + "__doc__"
exec(proper_string)
Essentially, I am going through a series of exercises and one of them asks to provide a short description of the entered function using the __ doc__ attribute. I am trying with abs.__ doc__ but my command line comes empty. When I run python in the command line and type in abs.__ doc__ without anything else it works, but for some reason when I try to input it as a string into the exec() command I can't get any output. Any help would be greatly appreciated. (I have deliberately added spaces in this description concerning the attribute I am trying to use because I get bold type without any of the underscores showing.)
As a note, I do not think I have imported any libraries that could interfere, but these are the libraries that I have imported so far:
import sys
import datetime
from math import pi
My Python version is Python 3.10.4. My operating system is Windows 10.
abs.__doc__ is a string. You should use eval instead of exec to get the string.
Example:
function = input("Please enter the name of a function: ")
proper_string = str(function) + "." + "__doc__"
doc = eval(proper_string)
You can access it using globals():
def func():
"""Func"""
pass
mine = input("Please enter the name of a function: ")
print(globals()[mine].__doc__)
globals() return a dictionary that keeps track of all the module-level definitions. globals()[mine] is just trying to lookup for the name stored in mine; which is a function object if you assign mine to "func".
As for abs and int -- since these are builtins -- you can look it up directly using getattr(abs, "__doc__") or a more explicit: getattr(__builtins__, "abs").__doc__.
There are different ways to lookup for a python object corresponding to a given string; it's better not to use exec and eval unless really needed.

QCheckbox issue [duplicate]

I am struggling to get this working.
I tried to transpose from a c++ post into python with no joy:
QMessageBox with a "Do not show this again" checkbox
my rough code goes like:
from PyQt5 import QtWidgets as qtw
...
mb = qtw.QMessageBox
cb = qtw.QCheckBox
# following 3 lines to get over runtime errors
# trying to pass the types it was asking for
# and surely messing up
mb.setCheckBox(mb(), cb())
cb.setText(cb(), "Don't show this message again")
cb.show(cb())
ret = mb.question(self,
'Close application',
'Do you really want to quit?',
mb.Yes | mb.No )
if ret == mb.No:
return
self.close()
the above executes with no errors but the checkbox ain't showing (the message box does).
consider that I am genetically stupid... and slow, very slow.
so please go easy on my learning curve
When trying to "port" code, it's important to know the basis of the source language and have a deeper knowledge of the target.
For instance, taking the first lines of your code and the referenced question:
QCheckBox *cb = new QCheckBox("Okay I understand");
The line above in C++ means that a new object (cb) of type QCheckBox is being created, and it's assigned the result of QCheckBox(...), which returns an instance of that class. To clarify how objects are declared, here's how a simple integer variable is created:
int mynumber = 10
This is because C++, like many languages, requires the object type for its declaration.
In Python, which is a dynamic typing language, this is not required (but it is possible since Python 3.6), but you still need to create the instance, and this is achieved by using the parentheses on the class (which results in calling it and causes both calling __new__ and then __init__). The first two lines of your code then should be:
mb = qtw.QMessageBox()
cb = qtw.QCheckBox()
Then, the problem is that you're calling the other methods with new instances of the above classes everytime.
An instance method (such as setCheckBox) is implicitly called with the instance as first argument, commonly known as self.
checkboxInstance = QCheckBox()
checkboxInstance.setText('My checkbox')
# is actually the result of:
QCheckBox.setText(checkboxInstance, 'My checkbox')
The last line means, more or less: call the setText function of the class QCheckBox, using the instance and the text as its arguments.
In fact, if QCheckBox was an actual python class, setText() would look like this:
class QCheckBox:
def setText(self, text):
self.text = text
When you did cb = qtw.QCheckBox you only created another reference to the class, and everytime you do cb() you create a new instance; the same happens for mb, since you created another reference to the message box class.
The following line:
mb.setCheckBox(mb(), cb())
is the same as:
QMessageBox.setCheckBox(QMessageBox(), QCheckBox())
Since you're creating new instances every time, the result is absolutely nothing: there's no reference to the new instances, and they will get immediately discarded ("garbage collected", aka, deleted) after that line is processed.
This is how the above should actually be done:
mb = qtw.QMessageBox()
cb = qtw.QCheckBox()
mb.setCheckBox(cb)
cb.setText("Don't show this message again")
Now, there's a fundamental flaw in your code: question() is a static method (actually, for Python, it's more of a class method). Static and class methods are functions that don't act on an instance, but only on/for a class. Static methods of QMessageBox like question or warning create a new instance of QMessageBox using the provided arguments, so everything you've done before on the instance you created is completely ignored.
These methods are convenience functions that allow simple creation of message boxes without the need to write too much code. Since those methods only allow customization based on their arguments (which don't include adding a check box), you obviously cannot use them, and you must code what they do "under the hood" explicitly.
Here is how the final code should look:
# create the dialog with a parent, which will make it *modal*
mb = qtw.QMessageBox(self)
mb.setWindowTitle('Close application')
mb.setText('Do you really want to quit?')
# you can set the text on a checkbox directly from its constructor
cb = qtw.QCheckBox("Don't show this message again")
mb.setCheckBox(cb)
mb.setStandardButtons(mb.Yes | mb.No)
ret = mb.exec_()
# call some function that stores the checkbox state
self.storeCloseWarning(cb.isChecked())
if ret == mb.No:
return
self.close()

Why can't I access a variable that's being returned from a function?

I am new to Python and am at a lost as to what I'm doing wrong. I am trying to use the fqdn variable that is being returned to the caller which is main() but I'm getting NameError: name 'fqdn' is not defined
I'm betting this is some type of global variable statement issue or something like that, but I've been researching this and can't figure it out.
If a function from a module returns a value, and the caller is main(), shouldn't main() be able to use that returned value???
Here's the layout:
asset.py
def import_asset_list():
# Open the file that contains FQDNs
openfile = open(r"FQDN-test.txt")
if openfile.mode == 'r':
# Remove CR from end of each item
fqdn = openfile.read().splitlines()
# Add https to the beginning of every item in list
fqdn = ["https://" + item for item in fqdn]
openfile.close()
return fqdn
tscan.py
def main():
import asset
asset.import_asset_list()
# Iterate through list
for i in fqdn:
if SCHEDULED_SCAN == 1:
create_scheduled_scan(fqdn)
launch_scan(sid)
check_status_scan(uuid)
else:
create_scan(fqdn)
launch_scan(sid)
check_status_scan(uuid)
Short Explanation
Yes, main() should be able to use the returned value, but it's only the value that is returned, not the variable name. You have to define a variable of your own name, to receive the value, and use that instead.
Long Explanation
The name of a variable inside any function is simply a "label" valid only within the scope of this function. A function is an abstraction which means "Give me some input(s), and I will give you some output(s)". Within the function, you need to reference the inputs somehow and, potentially, assign some additional variables to perform whatever it is you would like to. These variable names have no meaning whatsoever outside the function, other than to, at most, convey some information as to the intended use of the function.
When a function returns a value, it does not return the "name" of the variable. Only the value (or the reference in memory) of the variable. You can define your own variable at the point where you call the function, give it your own name and assign to it the returned result of the function, so you simply have to write:
def main():
import asset
my_asset_list = asset.import_asset_list()
# Iterate through list
for i in my_asset_list:
if SCHEDULED_SCAN == 1:
create_scheduled_scan(my_asset_list)
launch_scan(sid)
check_status_scan(uuid)
else:
create_scan(my_asset_list)
launch_scan(sid)
check_status_scan(uuid)
I don't know where the uuid and the sid variables are defined.
To make sure you have understood this properly, remember:
You can have multiple functions in the same file, and use identically-named variables within all those functions, this will be no problem because a variable (with its name) only exists within each specific function scope.
Variable names do not "cross" the boundaries of the scope, only variable values/references and to do this, a special construct is used, i.e. the return [something] statement.

Will class variable reset to initial value on its own in python?

Will class variable ever reset on its own when instance for that particular class is still present?
I have a class and during instantiating an object, I update class variable within init for future use where I would not have access to the instantiated object. I know for a fact that the object is no out of scope when I try to access this class variable. Sample snippet is given below.
Class A:
var = ""
def __init__(self,name):
self.name = name
A.var = name
A_obj = A("John")
I want to use var (which is "John") at a later part. when I get to that part, value of "A.var" is "" and not "John" as I expected The complete code is complicated to be posted here. So I have just provided basic scenario of what is happening
No.
Rather than a working example which would let us reproduce the symptom you see, you chose to provide code which works as documented and never shows the symptom, leaving us to guess about your situation. I enclose my guess, a slightly longer version of your code:
def empty():
print('empty')
return ''
class A:
var = empty()
def __init__(self, name):
self.name = name
A.var = name
obj_john = A('John')
print(A.var)
obj_mary = A('Mary')
print(A.var)
The big difference is logging of the empty string assignment, which seems to be your chief concern. Unsurprisingly, the output produced is:
empty
John
Mary
That is, the empty string was assigned exactly once, and then the ctor repeatedly overwrote the singleton.
If you abuse repeated imports of your module then you might manage to invoke the empty assignment twice, but you haven't described any of those interactions. Setting a debugger watchpoint might prove useful. Dig a bit further, and share with us what you found.

Changing value and importing - Doesn't save new value

I'm using latest python version; I have a simple function in one file, then another file calls that function. Problem is the variable from function isn't printed.
file1.py:
var = "one"
def first():
global var
if smt == True:
var = "1"
else:
var = "W"
file2.py:
from file1 import *
first()
print(var)
This is simplified version because I have more irrelevant code, but the problem is still the same, my variable doesn't change for some reason.
The practice of using import * is usually discouraged; due to the fact that it might be prone to namespace collisions, inefficient if the import is huge et cetera.
I would personally go for an explicit import: from file1 import first
I also believe that you have the wrong idea of what global is. This might help:
In the first case the global keyword is pointless, so that is not
correct. Defining a variable on the module level makes it a global
variable, you don't need to global keyword.
The second example is correct usage.
However, the most common usage for global variables are without using
the global keyword anywhere. The global keyword is needed only if you
want to reassign the global variables in the function/method.
Keep in mind that you do not have var in file2.py by simply using global keyword; if you'd like to access the variable var you can use something like:
In file1.py:
var = "one"
def first():
global var
var = "1"
In file2.py:
import file1
file1.first()
print(file1.var)

Resources