Share data between an external function and a python class function - python

I want to share a variable value between a function defined within a python class and an externally defined function. So in the code below, when the internalCompute() function is called, self.data is updated. How can I access this updated data value inside a function that is defined outside the class, i.e inside the report function?
Note:
I would like to avoid using of global variable as much as possible.
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute():
q = Compute()
q.internalCompute()
def report():
# access the updated variable self.data from Compute class
print "You entered report"
externalCompute()
report()

It's a good idea to avoid magic globals, but your report() function must have some way to know where to look. If it's ok to pass it the object doing the computation, i.e. q, it can simply print out q.data. If not, then you can arrange for q to save its data in the class itself-- obviously this means that the class can only be instantiated once, so I would go with the first option.

You can't do that unless you instantiate the class somewhere.
Currently in your implementation you instantiate the Compute class here:
def externalCompute():
q = Compute()
q.internalCompute()
But as soon as the function finishes q goes out of scope and is destroyed so you will lose all information that the class contains. In order to do what you want to do the Compute class has to be instantiated to not be local to a function (or your function needs to return the instance of the Compute class as to preserve its state.)
Usually you would do that by having one "main" if your python file in this way:
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute(q):
q.internalCompute()
def report(q):
# access the updated variable self.data from Compute class
data = q.data
print "You entered report"
if __name__ == '__main__':
q = Compute()
externalCompute(q)
report(q)

You actually have access to the data through q.data, you just have to return it.
Change your code to reflect that fact:
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute():
q = Compute()
q.internalCompute()
return q.data
def report():
print externalCompute()
report() # 5
If you don't like this approach, you have only a few other options:
Global variable.
Instantiating another class.
Updating the same class you instantiated.
Database.
Pickle.

Related

Calling a function within one class that calls a function within a separate class python

I am having trouble trying to call a function with one class that calls a separate function that exists within another class.
class PrintNum():
def get_square(self):
Numbers.square_Num(self)
def Print_Num(self):
Numbers.square_Num(self)
class Numbers():
def __init__(self, num1,num2):
self.num1=num1
self.num2=num2
def show_num(self):
return self.num1,self.mum2,
def square_Num(self):
self.num1,self.mum2, = self.num1**2,self.num2**2
p2= PrintNum(3,6)
p2.get_square()
print(p2.Print_Num)
To Get Such Behaviour from your classes, You need to use either inheritance or Embed the class. I used embedding to solve the problem above although I feel inheritance might be better suited here.
class PrintNum():
def __init__(self,a1,a2):
self.numbers = Numbers(a1,a2)
def get_square(self):
self.numbers.square_Num(self)
def Print_Num(self):
print(self.numbers)
class Numbers():
def __init__(self, num1,num2):
self.num1=num1
self.num2=num2
def __repr__(self):
print(self.num1)
return self.num2
def square_Num(self,*args,**kwargs):
self.num1,self.num2 = self.num1**2,self.num2**2
p2= PrintNum(3,6)
p2.get_square()
p2.Print_Num()
You want something like this:
class PrintNum:
def get_square(self):
Numbers().square_Num()
def Print_Num(self):
Numbers().square_Num()
The methods of the Numbers class are instance methods - they need to be called on an instance of the class, not the class itself. We make an instance by calling the class:
numbers_instance = Numbers()
So in PrintNum's methods we create an instance of Numbers before calling the methods.
In this case, you are not using classes correctly. The parameter self references the object instance you created of the given class. You should not try to access it outside of the instance methods of a class. Trying to pass the self parameter to a different class will not work because they would represent two different object instances. In this case, you never instantiate a Numbers object at all, so it has no instance. To do this properly, instantiate a Numbers instance inside of PrintNum and then call its instance methods like so:
class PrintNum():
def __init__(self):
self.numbers = Numbers()
def get_square(self):
return self.numbers.square_number()
def print_number(self):
return self.numbers.show_num()
class Numbers():
def __init__(self):
self.num1=2
self.num2=3
def show_num(self):
return self.num1,self.mum2
def square_number(self):
self.num1,self.mum2 = self.num1**2,self.num2**2
p2= PrintNum()
p2.get_square()
print(p2.print_number())

How to access variable of a nested functions in python?

I need to access a variable which is set in a nested function. I'm reading this variable data from another thread. What is the best way to obtain the data without doing any scope violation?
Here is the code snippet,
class main(object):
def sub_fun(self):
def inner_fun(self):
self.var = 10
inner_fun(self)
p = main().sub_fun()
Now how to access the var attribute of p?
class main(object):
def sub_fun(self):
def inner_fun(self):
self.var = 10
p = main()
You cannot access the nested function's variable because its a closure & is accessible only to the immediate parent. var is only accessible by inner_fun. See below for a different implementation.
class main(object):
def outer_function(self):
def inner_function(self):
self.x = 10
return self.x
out = inner_function(self) # Accessing the inner function
return out
p = main()
q = p.outer_function()
print(q)
If there is a need for a class object or a parent function to access a variable inside a child nested function, then the variable should be hoisted to the outer scope by returning it. Otherwise the scope of the variable will reside only in the so called child nested function.
The problem is that main.sub_fun returns None. There are two simple workarounds:
Just store a reference to the item you create before calling the method:
p = main()
p.sub_fun()
print(p.var)
This is the best option in my opinion.
If you really want the one line version to work, return self from sub_fun:
def sub_fun(self):
def inner_fun():
self.var = 10
inner_fun()
return self
print(main().sub_fun().var)
In neither case do you need to pass self to inner_fun. It will always look into the outer scope when the local name is not found. #2 shows an example of this.

How to initialise class attributes?

I currently have the following two ways:
class Venue:
store = Database.store()
ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
OR
class Venue:
#classmethod
def set_venue_ids(cls):
store = Database.store()
cls.ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
And before using/instantiating the class I would call:
Venue.set_venue_ids()
What would be the correct way of achieving this?
If it's the first way, what would I do if the instantiation of the attribute required more complex logic that could be done more simply through the use of a function?
Or is there an entirely different way to structure my code to accomplish what I'm trying to do?
From a purely technical POV, a class is an instance of its metaclass so the metaclass initializer is an obvious candidate for class attributes initialization (at least when you have anything a bit complex).
Now given the canonical lifetime of a class object (usually the whole process), I would definitly not use an attribute here - if anyone adds or removes venues from your database while your process is running, your ids attributes will get out of sync. Why don't you use a classmethod instead to make sure your data are always have up to date ?
Oh and yes, another way to construct your Venue.ids (or any other class attribute requiring non-trivial code) without having complex code at the class top-level polluthing the class namespace (did you noticed that in your first example store becomes a class attributes too, as well as vid if using Python 2.x ?) is to put the code in a plain function and call that function from within your class statement's body, ie:
def list_venue_ids():
store = Database.store()
# I assume `store.find()` returns some iterator (not a `list`)
# if it does return a list, you could just
# `return store.find(...)`.
return list(store.find(Venue.id, Venue.type == "Y"))
class Venue(object):
ids = list_venue_ids()
def __init__(self):
self.a = 1
self.b = 2

understanding method use inside a class

I'm new to classes, this is a small piece of code I've written, but I'm still really shaky on this concept, and am wondering exactly how the method node_name comes into play here and if it's even needed?
from rdflib import BNode
class HigherNode(object):
def node_name(name):
return name
def __init__(self, **kwargs):
self.node_type = kwargs.get('node_type', 'cog_con')
self.position = kwargs.get('position', 0)
self.node_id = self.node_name
self.node = kwargs.get(self.node_name(), BNode())
for key, value in kwargs.items():
setattr(self, key, value)
def __str__(self):
return 'This is the node of {} in the graph'.format(self.node_id)
I behavior that I'm seeking is something equivalent to this:
elephant = BNode()
when used as:
some_node = HigherNode(node_id = 'elephant')
So, first off, methods have to be called by an instance of the class. So, your behavior would look something like this:
# create an instance
node = HigherNode()
# get the name
print node.node_name()
However, you never declared name inside the class. So, you'll have to do something like this:
def node_name(self):
return self.name
(All instances pass a reference to themselves to thier functions when called, so you'll always have to have at least one variable in the function call. You don't have to call it self.)
Really, it looks like what you want is actually a name setter/getter.
Try this:
Declare/set the variable in __init__.
def __init__(self, **kwargs):
self.node_name= kwargs.get('node_name', None)
Then you can use the variable like this:
# create an instance
node = HigherNode()
# get the name
print node.node_name
# set the name
node.node_name = "bluh"
Since your class extends object, use getter/setter properties.
#property
def node_name(self):
return self.node_name
#node_name.setter
def node_name(self, x):
self.node_name = str(x)
These are called exactly the same as above in option 1:
# create an instance
node = HigherNode()
# get the name
print node.node_name
# set the name
node.node_name = "bluh"
I prefer this method, since it allows you much more control over how things are set, or even whether or not you can set or get them! (Just make a getter property without a corresponding setter property, for instance.)
However, this second method is more work to set up and may not be suitable for simple variables.

Fudging the line between classes and functions

I have a series of functions that serve to classify data. Each function is passed the same input. The goal of this system is to be able to drop in new classification functions at will without having to adjust anything.
To do this, I make use of a classes_in_module function lifted from here. Then, every classifier in one python file will be ran on each input.
However, I am finding that implementing the classifier as either a class or a function is kludgy. Classes mean instantiating and executing, while functions lack clean introspection to allow me to query the name or use inheritance to define common values.
Here is an example. First, the class implementation:
class AbstractClassifier(object):
#property
def name(self):
return self.__class__.__name__
class ClassifierA(AbstractClassifier):
def __init__(self, data):
self.data = data
def run(self):
return 1
This can then be used in this fashion, assuming that classifier_list is the output of classes_in_module on a file containing ClassifierA among others:
result = []
for classifier in classifier_list:
c = classifier(data)
result.append(c.run())
However, this seems a bit silly. This class is obviously static, and doesn't really need to maintain its own state, as it is used once and discarded. The classifier is really a function, but then I lose the ability to have a shared name property -- I would have to use the ugly introspection technique sys._getframe().f_code.co_name and replicate that code for each classifier function. And any other shared properties between classifiers would also be lost.
What do you think? Should I just accept this mis-use of classes? Or is there a better way?
Functions can have member data. You can also find the name of a function using the func_name attribute.
def classifier(data):
return 1
classifier.name = classifier.func_name
print(classifier.name) #classifier
If you want multiple functions to behave the same way, you can use a decorator.
function_tracker = []
def add_attributes(function):
function.name = function.func_name
function.id = len(function_tracker)
function_tracker.append(function)
return function
#add_attributes
def classifier(data):
return 1
print(classifier.name, classifier.id) # 'classifier', 0
Would this work to avoid classes in your specific case?
If you don't need several instances of the class (and it seems you don't) make one instance of the class and change the run to __call__:
class AbstractClassifier(object):
#property
def name(self):
return self.__class__.__name__
class ClassifierA(AbstractClassifier):
def __call__(self, data):
return 1
ClassifierA = ClassifierA() # see below for alternatives
and then in your other code:
result = []
for classifier in classifier_list:
result.append(classifier(data))
Instead of having ClassifierA = ClassifierA() (which isn't very elegant), one could do:
classifier_list = [c() for c in (ClassifierA, ClassifierB, ...)]
This method allows you to keep your classes handy should you need to create more instances of them; if you don't ever need to have more than one instance you could use a decorator to IAYG (instantiate as you go ;) :
def instantiate(cls):
return cls()
#instantiate
class ClassifierZ(object):
def __call__(self, data):
return some_classification
To use a class instance as a function:
class ClassifierA(AbstractClassifier):
def __init__(self, data):
self.data = data
def __call__(self):
return 1
result = []
for classifier in classifier_list:
c = classifier(data)
result.append(c())
Or to just use functions:
classifier_list = []
def my_decorator(func):
classifier_list.append(func)
return func
#my_decorator
def classifier_a(data):
return 1
result = []
for classifier in classifier_list:
c = classifier(data)
result.append(c)

Categories

Resources