Pass in two variables to **kwargs - python-3.x

Say I have an entry form for a GUI window that asks for a new setting and a value for that setting, which it then passes to another object that manages settings and expects **kwargs as input:
class SettingsForm(someFormClass):
def onSubmit(self):
new_setting = self.content['new setting'].get()
new_value = self.content['value'].get()
settings_instance.add_setting(new_setting=new_value)
This sets new_value to the literal string 'new_setting'. I've tried various ways to get around this, such as using a dictionary:
class SettingsForm(someFormClass):
def onSubmit(self):
new_setting = self.content['new setting'].get()
new_value = self.content['value'].get()
mydict = {}
mydict[new_setting] = new_value
settings_instance.add_setting(**mydict)
This works, but doesn't make much sense for a single pair of values... is there an obvious way that I'm missing?

Related

Dictionary to switch between methods with different arguments

A common workaround for the lack of a case/switch statement in python is the use of a dictionary. I am trying to use this to switch between methods as shown below, but the methods have different argument sets and it's unclear how I can accommodate that.
def method_A():
pass
def method_B():
pass
def method_C():
pass
def method_D():
pass
def my_function(arg = 1):
switch = {
1: method_A,
2: method_B,
3: method_C,
4: method_D
}
option = switch.get(arg)
return option()
my_function(input) #input would be read from file or command line
If I understand correctly, the dictionary keys become associated with the different methods, so calling my_function subsequently calls the method which corresponds to the key I gave as input. But that leaves no opportunity to pass any arguments to those subsequent methods. I can use default values, but that really isn't the point. The alternative is nested if-else statements to choose, which doesn't have this problem but arguably less readable and less elegant.
Thanks in advance for your help.
The trick is to pass *args, **kwargs into my_function and the **kwargs onto to your choosen function and evaluate it there.
def method_A(w):
print(w.get("what")) # uses the value of key "what"
def method_B(w):
print(w.get("whatnot","Not provided")) # uses another keys value
def my_function(args,kwargs):
arg = kwargs.get("arg",1) # get the arg value or default to 1
switch = {
1: method_A,
2: method_B,
}
option = switch.get(arg)
return option(kwargs)
my_function(None, {"arg":1, "what":"hello"} ) # could provide 1 or 2 as 1st param
my_function(None, {"arg":2, "what":"hello"} )
Output:
hello
Not provided
See Use of *args and **kwargs for more on it.

How to use a variable "holding" a string value as list name?

One of the parameter the I want to pass to a Class init is a variable with a string value. this string value is a name of a list. The init should use this string value to append the class object to that list. what I'm doing wrong?
I've tried using the locals() and globals() but it ended with "TypeError: unhashable type: 'list'". tried also vars() with no use as well.
refList = []
cmpList = []
class Part(object):
def __init__(self, origin, name, type, listName):
self.origin = origin
self.name = name
self.type = type
partListName = locals()[listName]
partListName.append(self)
#... some file parsing..
part1 = Part((str(origin), str(name) ,str(type), 'refList')
# ... some other file parsing ...
part2 = Part((str(origin), str(name) ,str(type), 'cmpList')
Welcome to SO Ram! I think you should rethink your code because this is not a good approach to do it always. It is better for example pass directly the list or something related.
However your issue with your code is that you should use the globals() function. I really recommend you see the next post in order to get more knowledge about how/when use this useful functionality of Python3.
Also, you must declarate your variables with global keywoard because you are going to reference this variables from your Part class.
global refList = []
global cmpList = []
Said all this, your critical code line should look like:
partListName = globals()[listName]

How can I make this body of code through a for loop?

So, I'm trying to get this code to work in a cleaner way, mainly, through the use of a for loop, but having a really hard time trying to do so. I haven't been able to make a loop that assigns each value of the dictionary to a correspondent variable, so it can be used in the class. For context, the dictionary contains values obtained from another class, I just put those in the dict and sent it to this class, so I don't need to calculate those again.
def get_ipr_data(self):
self.reservoir_result_dict = ReservoirDataFrame.reservoir_result_dict
self.pb = self.reservoir_result_dict.get("pb")
self.rs = self.reservoir_result_dict.get("rs")
self.bo = self.reservoir_result_dict.get("bo")
self.uo = self.reservoir_result_dict.get("uo")
self.re = self.reservoir_result_dict.get("re")
self.j_index = self.reservoir_result_dict.get("j_index")
self.q_max = self.reservoir_result_dict.get("q_max")
self.pws = self.reservoir_result_dict.get("pws")
self.qb = self.reservoir_result_dict.get("qb")
You can use setattr function
for name in ["pb", "rs", "bo", "uo", "re", "j_index", "q_max", "pws", "qb"]:
setattr(self, name, self.reservoir_result_dict.get(name))
Documentation of setattr:
https://docs.python.org/3/library/functions.html#setattr
Delegating attributes is done by defining the __getattr__ method. You should store the dictionary only and then define __getattr__.
class Foo:
...
def get_ipr_data(self):
self.reservoir_result_dict = ReservoirDataFrame.reservoir_result_dict
def __getattr__(self, item):
return self.reservoir_result_dict[item]

Access element of list by variable name

How can I access a list element using the name of the list?
I would like to allow a user to edit the code in determine a single variable to be inputted into a function. For example:
blah = [1,2]
blah2 = 5
toBeChanged = "blah2"
def foo():
print(blah)
def changeVariable():
globals()[toBeChanged] += 1
for time in range(5):
changeVariable()
simulate
This works for blah2 since it is a simple variable, however it will not work for blah[0] since it is part of a list. I've also tried placing my variables into a dictionary as other answers have suggested, but I still am unable to change list elements through a simple string.
Is there a way to do this that I am missing? Thanks!
Rather than using globals() and altering directly it would be much, much better to use a dictionary to store the variables you want the user to alter, and then manipulate that:
my_variables = {
'blah': [1,2]
'blah2': 5
}
toBeChanged = "blah2"
def foo():
print(my_variables['blah'])
def changeVariable():
my_variables[toBeChanged] = my_variables.get(toBeChanged,0) + 1
for time in range(5):
changeVariable()
This has the added advantage that if a user enters a variable that doesn't exist a default is chosen, and doesn't override any variables that might be important for future execution.

Python: pulling a reference from a list of objects with the for loop [duplicate]

This question already has answers here:
Why does comparing strings using either '==' or 'is' sometimes produce a different result?
(15 answers)
Closed 8 years ago.
So I am pretty new to python so be kind.
I am trying to create a global sort of object directory as a base for all my programs as a means to keep track of all created object instances in my programs.
so..
I create a class that holds a list of object references ( not id's ).
example:
class objDirectory:
name = ""
count = 0
objDir = []
def __init__( self ):
print( "Initiating object directory." )
name = "objDirectory"
self.count= 1
self.objDir = [ self ]
return
def getObj( self, name ):
print( "Searching directory for:", name )
for o in self.objDir:
if o.name is name:
print( "Returning:", name )
return obj
else:
print( "Search failed" )
return
But, once an object is added to a list and I run the get script it does not return my object. I even verify by using directory.objDir[x]. ( this always references my object) .
What am I not doing, or doing wrong?
Thanks.
Results:
setDirectory()
Initiating object directory.
Global directory reference set
test = obj( "test" )
Initiating: test
Duplicate check
Logging: test1
Object count: 2
t1 = directory.getObj( "test1" )
Searching directory for: test1
Search failed
print( directory.objDir )
[<main.objDirectory object at 0x032C86F0>, <main.obj object at 0x032C8710>]
I don't quite understand how you plan to use this object, however I find that there are a few problems with the __init__ method.
First of all, I guess that your object should be a singleton, however it is not. You define the class attributes here:
class objDirectory:
name = ""
count = 0
objDir = []
But in your __init__ method you always override them, instead of adding to them. This means that every time you will write something like a=objDirectory(), count will be set to 1 for that instance. Also, notice that (at least in python2.7), you'll need a #classmethod decorator for every function you wish be able to modify class attributes (as opposed to the instance's attributes). Like so:
class objDirectory:
count=0
#classmethod
def add_object(cls):
cls.count+=1
def __init__(self):
self.add_object()
This goes for objDir as well.
Second, in your __init__ method, you have a variable called name, which is never used. Perhaps you meant self.name?
There are better ways to implement singletons, however here is a simple example that might be easier to understand if you're new to python:
class mySingleton(object):
singletonObject = None
def __new__(cls):
if not cls.singletonObject:
cls.singletonObject = super(mySingleton, cls).__new__(cls)
return cls.singletonObject
The __new__ method is a static method which creates the actual instance. The return value is the new instance created. Overriding it like so will let me get the same instance for each call to mySingleton(); the statement mySingleton() is mySingleton() will always be true.

Resources