python subprocess Process target function won't instantiate classes - python

I am trying to launch several operations in parallel using subprocess.Process. The problem I am having is that if I try to instantiate an instance of my class in the target function nothing happens. But, if I instantiate the classes first and pass the instances to the target function then everything works. Here is an abstraction of what I am doing
Instantiate before launching Process: everything works
def spawn(my_class_instance):
my_class_instance.launch()
for params in my_list_of_parameters:
an_instance = MyClass(params)
Process(target=spawn, args=(an_instance)).start()
Instantiate inside target function: doesn't work
def spawn(params):
an_instance = MyClass(params)
an_instance.launch()
for params in my_list_of_parameters:
Process(target=spawn, args=(params)).start()
I'd really like to understand more about why it doesn't work to try to instantiate classes inside the target function. Is it related to immediately calling Process.start()? What is happening under the hood that is preventing this?
One thing that might be causing this is that each MyClass.launch() itself calls subprocess.Popen(..., shell=False), in case this might be the reason. If so, why? It still gets called in the first case.
Thanks!

This works. Still, I may be something in your question.
from multiprocessing import Process
class MyClass:
def __init__(self, params):
pass
def launch(self):
print "method launch is called"
def spawn(params):
an_instance = MyClass(params)
an_instance.launch()
my_list_of_parameters = ['1', '2']
for params in my_list_of_parameters:
Process(target=spawn, args=(params)).start()

Related

Cleanest way to reset a class attribute

I have a class that looks like the following
class A:
communicate = set()
def __init__(self):
pass
...
def _some_func(self):
...some logic...
self.communicate.add(some_var)
The communicate variable is shared among the instances of the class. I use it to provide a convenient way for the instances of this class to communicate with one another (they have some mild orchestration needed and I don't want to force the calling object to serve as an intermediary of this communication). However, I realized this causes problems when I run my tests. If I try to test multiple aspects of my code, since the python interpreter is the same throughout all the tests, I won't get a "fresh" A class for the tests, and as such the communicate set will be the aggregate of all objects I add to that set (in normal usage this is exactly what I want, but for testing I don't want interactions between my tests). Furthermore, down the line this will also cause problems in my code execution if I want to loop over my whole process multiple times (because I won't have a way of resetting this class variable).
I know I can fix this issue where it occurs by having the creator of the A objects do something like
A.communicate = set()
before it creates and uses any instances of A. However, I don't really love this because it forces my caller to know some details about the communication pathways of the A objects, and I don't want that coupling. Is there a better way for me to to reset the communicate A class variable? Perhaps some method I could call on the class instead of an instance itself like (A.new_batch()) that would perform this resetting? Or is there a better way I'm not familiar with?
Edit:
I added a class method like
class A:
communicate = set()
def __init__(self):
pass
...
#classmethod
def new_batch(cls):
cls.communicate = set()
def _some_func(self):
...some logic...
self.communicate.add(some_var)
and this works with the caller running A.new_batch(). Is this the way it should be constructed and called, or is there a better practice here?

How to avoid circular reference in python - a class member creating an object of another class and passing self as parameter?

I need some help in terms of 'pythonic' way of handling a specific scenario.
I'm writing an Ssh class (wraps paramiko) that provides the capability to connect to and executes commands on a device under test (DUT) over ssh.
class Ssh:
def connect(some_params):
# establishes connection
def execute_command(command):
# executes command and returns response
def disconnect(some_params):
# closes connection
Next, I'd like to create a Dut class that represents my device under test. It has other things, besides capability to execute commands on the device over ssh. It exposes a wrapper for command execution that internally invokes the Ssh's execute_command. The Ssh may change to something else in future - hence the wrapper.
def Dut:
def __init__(some params):
self.ssh = Ssh(blah blah)
def execute_command(command)
return self.ssh.execute_command(command)
Next, the device supports a custom command line interface for device under test. So, a class that accepts a DUT object as an input and exposes a method to execute the customised command.
def CustomCli:
def __init__(dut_object):
self.dut = dut_object
def _customize(command):
# return customised command
def execute_custom_command(command):
return self.dut.execute_command(_customize(command))
Each of the classes can be used independently (CustomCli would need a Dut object though).
Now, to simplify things for user, I'd like to expose a wrapper for CustomCli in the Dut class. This'll allow the creator of the Dut class to exeute a simple or custom command.
So, I modify the Dut class as below:
def Dut:
def __init__(some params):
self.ssh = Ssh(blah blah)
self.custom_cli = Custom_cli(self) ;# how to avoid this circular reference in a pythonic way?
def execute_command(command)
return self.ssh.execute_command(command)
def execute_custom_command(command)
return self.custom_cli.execute_custom_command(command)
This will work, I suppose. But, in the process I've created a circular reference - Dut is pointing to CustomCli and CustomCli has a reference to it's creator Dut instance. This doesn't seem to be the correct design.
What's the best/pythonic way to deal with this?
Any help would be appreciated!
Regards
Sharad
In general, circular references aren't a bad thing. Many programs will have them, and people just don't notice because there's another instance in-between like A->B->C->A. Python's garbage collector will properly take care of such constructs.
You can make circular references a bit easier on your conscience by using weak references. See the weakref module. This won't work in your case, however.
If you want to get rid of the circular reference, there are two way:
Have CustomCLI inherit from Dut, so you end up with just one instance. You might want to read up on Mixins.
class CLIMerger(Dut):
def execute_custom_command(command):
return self.execute_command(_customize(command))
# use self^ instead of self.dut
class CLIMixin(object):
# inherit from object, won't work on its own
def execute_custom_command(command):
return self.execute_command(_customize(command))
# use self^ instead of self.dut
class CLIDut(Dut, CLIMixin):
# now the mixin "works", but still could enhance other Duts the same way
pass
The Mixin is advantageous if you need several cases of merging a CLI and Dut.
Have an explicit interface class that combines CustomCli and Dut.
class DutCLI(object):
def __init__(self, *bla, **blah):
self.dut = Dut(*bla, **blah)
self.cli = CustomCLI(self.dut)
This requires you to write boilerplate or magic to forward every call from DutCLI to either dut or cli.

Python - list resets as I update it

I'm trying to append data to a list but right before I append a new value the list seems to reset. Here's the relevant code:
This is the main module:
def update():
global url
data.add_price(df.pulldata(url))
This is the data module:
historical_price = []
def add_price(price):
historical_price.append(price)
print(historical_price)
I am guessing that the problem is the fact that I am defining historical_price to be empty at the top. This however confuses me, since that whole script is never run. How do I go about fixing this? Hints are appreciated.
You never instantiate the data class, so it's performing add_price without an instance to perform it on. You should add self as a parameter to add_price and you should instantiate your data class something like this.
d = data()
def update():
global url
d.add_price(df.pulldata(url))
You should also make historical_price an attribute of the data class, so the data class should look something like this.
class data:
def __init__(self):
self.historical_price = []
def add_price(self, price):
self.historical_price.append(price)
print(self.historical_price)
Since your add_price function is in a different module, this part historical_price = [] is run everytime you invoke that method.
Invoking a global function executes all global code first, then executes the function.
To fix this, you could:
Write a class with that list as an instance variable and instantiate it in your main code.
Write that class and make the method static, using the list as a class variable.
Define the gobal variable in your main code and hand it to the function as a parameter.
The main code is the top level code that controls the flow of the program by invoking methods and instantiating classes.

Difficulties with re-using a variable

here is a part of my code :
class projet(object):
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
valCouche = nameCouche() # asks for a positional argument but 'self' doesnt work
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
print(valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(valCouche))
So I would like to use valCouche in goLissage method but it doesnt work.
I thought that valCouche would have the argument of valLissage but instead it gives False as a value.
I've tried different alternatives but still doesnt work.
You've got multiple problems here.
First, if you write this in the middle of a class definition:
valCouche = nameCouche()
... you're creating a class attribute, which is shared by all instances, not a normal instance attribute.
Also, you're running this at class definition time. That means there is no self yet--there aren't any instances yet to be self--so you can't call a method like nameCouche, because you don't have anything to call it on.
What you want to do is call the method at instance initialization time, on the instance being initialized, and store the return value in an instance attribute:
def __init__(self):
self.valCouche = self.nameCouche()
Then, when you want to access this value in another method later, you have to access it as self.valCouche.
If you make those changes, it will work. But your object model still doesn't make much sense. Why is nameCouche a method when it doesn't have anything to do with the object, and doesn't access any of its attributes? Maybe it makes sense as a #staticmethod, but really, I think it makes more sense just as a plain function outside the class. In fact, none of the code you've written seems to have anything to do with the class.
This kind of cram-everything-into-the-class design is often a sign that you're trying to write Java code in Python, and haven't yet really understood how Python does OO. You might want to read a good tutorial on Python classes. But briefly: if you're writing a class just to have somewhere to dump a bunch of vaguely-related functions, what you want is a module, not a class. If you have some reason to have instances of that class, and the functions all act on the data of each instance, then you want a class.
You have to declare variabile in the __init__ method (constructor) and then use it in your code
ex:
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
self.valCouche = self.nameCouche()
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))
you have to define an initialization function: def__init__(self)
defining valCouche as an instance attribute make it accessible on all the method so we have the following
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
self.valCouche = float(ui.valLissage.displayText())
#staticmethod #here there is no need for self so it is a method of class
def choixTraitement():
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self):
if ui.chkboxLissage.isChecked():
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))

Cannot call method unless its global from a class

Hi I am new to Disco and integrating existing code to it. Is Disco capable to call map/reduce function as a function within a class instead of global function? The following code might explain more clearly.
class Segmenter(object):
def map_fun(line, params):
....
def reduce_fun(iter, params):
....
def disco_mp(self):
job = Job().run(input=["raw://word_to_segment_......"],
map=map_fun,
reduce=reduce_fun)
...
The result of execution is
NameError: global name 'map_fun' is not defined
But if I change map_fun, reduce_fun into global function, it would work fine as expected.
However I still have to find a way to make it work as class functions, is there any way to
do it ?
Thanks,
Chandler
You need static method, you can do this with decorator:
class Segmenter(Job):
map = staticmethod(map_fun)
reduce = staticmethod(reduce_fun)
#staticmethod
def map_fun(line, params):
....
#staticmethod
def reduce_fun(iter, params):
....
def disco_mp(self):
job = self.run(input=["raw://word_to_segment_......"])
Note that you will not have access to self in both map_fun and reduce_fun, and this is why params exists. Also note that Job.run is now self.run and Segmenter extends Job.
It looks like you want to use self.map_fun and self.reduce_fun. Methods of objects can't be accessed by their bare names in Python; you have to use self. You will also need to provide a self argument to those methods. You should read the Python tutorial to familiarize yourself with the basics of classes and methods in Python.
(Also, why is the title of your question unrelated to the actual question?)

Categories