Code using a variable like a function/method with ()? - python

I am looking at an existing code base that is using a bool variable like a method, for example:
class Manager(object):
def __init__(self):
self._on_elect_callback = None
self._on_revoke_callback = None
self.... = ... (..., event_listener = self._event)
def _event(self, type):
on_elect_callback = self._on_elect_callback
if type == SOME_CONSTANT:
....
if on_elect_callback:
on_elect_callback()
def do_this(self, on_elect_function):
self._on_elect_callback = on_elect_function
if self....:
on_elect_function()
Questions:
I am curious how that on_elect_callback is being used like a function with () after if condition on the last line. Isn't that some boolean variable? I searched the repo and there is no definition for that. What is it doing?
Also, I would like to set a variable in __init__ that the callback function of event can use like "hey this event type IS SOME_CONSTANT, so set the variable in __init__ to "ABCD" (or True), how can I achieve it? Is the way in the code above the way to do it?

The self._on_elect_callback was probably going to be assigned a function as in self._on_elect_callback = lambda: "I'm a function". I think the reason you think it was meant to be a variable is because it is used in an if expression. The reason is that if self._on_elect_callback gets assigned a function the expression will evaluate to True, as functions support a method bool, which returns True by default.
About Q2, sure you can, functions are objects in python, so you can pass them around to higher order functions, or assign them as variables as in the example
class Manager(object):
def __init__(self, function):
self._on_elect_callback = function # here we assigned the given function
if not function:
# here we define a default attribute using an anonymous function
self._on_elect_callback = lambda: "Default Function"
def _event(self, type):
if self._on_elect_callback:
self._on_elect_callback()

Related

Class objects contains both _<var> and <var> attributes when using property decorator

I have the following class. I want to keep _my_var = None if the user does not provide a value for that. They can use the setter to set it, where I enforce some validation
class A:
_my_var = None
#property
def my_var(self):
return self._my_var
#property.setter
def my_var(self, value)
# Some validation
return._my_var = value
I am creating an object in the following code
x = A()
When I look at the attributes x has
_my_var: None
my_var: None
When I set x._myvar = 10 both my_var and _my_var attributes are set to 10. I have a confusion about this. IS _my_var a field and my_var is a function? How can keep only _my_var as the attribute while enforcing the setter to set it?
It's because you made my_var a property, but in the function it returns self._my_var, so if you change the self._my_var to 10, and then you call the my_var function again, it would return the modified self._my_var value.
Setting the my_var function to a #property could confuse you, it acts like it's just attribute of the class, but it's actually a function, just it is called without parenthesis. If you make it a regular function without #property like:
def my_var(self):
return self._my_var
Then it would be more obvious that it's a function because you would call it like:
x._myvar = 10
print(x.my_var())
Would give:
10
This would make it more obvious.
To make it not change according to _my_var, change the function to an variable, so instead of:
def my_var(self):
return self._my_var
Make it:
self.my_var = int(self._my_var)

Instance variable as function of other instance variables

Is it possible to define an instance variable in a class as a function of another? I haven't gotten it to work unless you redefine the "function instance variable" all the time.
Basically you could have a scenario where you have one instance variable that is a list of integers, and want to have the sum of these as an instance variable, that automatically redefines every time the list is updated.
Is this possible?
class Example:
list_variable = []
sum_variable = sum(list_variable)
def __init__(self, list_variable):
self.list_variable = list_variable
return
This will result in sum_variable = 0 unless you change it.
I understand that this is far from a major issue, you could either define sum_variable as a method or redefine it every time you change list_variable, I'm just wondering if it's possible to skip those things/steps.
Python offers the property decorator for a syntatically identical use of your example:
class Example:
list_variable = []
def __init__(self, list_variable):
self.list_variable = list_variable
return
#property
def sum_variable(self):
return sum(self.list_variable)
e = Example(list_variable=[10, 20, 30])
e.sum_variable # returns 60

Best way to re-evaluate/update the truth value of a conditional expression passed as a class variable in Python

In my code I would like to create an "event" class. Upon initialization, an event is passed a condition for it to trigger. I would like the flexibility to have any boolean expression passed as a trigger. In simplest terms:
class event():
def __init__(self,condition,outcome):
self.condition = condition
self.outcome = outcome
def check(self):
if self.condition:
print(self.outcome)
Of course this is not quite right, because my intent is for the class to evaluate the original expression that was passed, and not its truth value at creation of the object. For example:
foo = 0
e = event(foo != 0,"foo has changed value")
e.check()
foo = 1
e.check()
The desired outcome is for the check method to print a statement when it is called the second time.
I am open to reworking the whole class conception, but the main purpose of designing things this way is that the set of possible outcomes of an event is reasonably small enough to encode with a few class variables, and the triggering conditions will be known at instantiation but could vary widely and incorporate objects from a range of classes.
One last bit of info: all variables that will go into the conditional statement will have been instantiated before the event object creation.
You want to pass a callable instead of the actual bool value, like this (type annotations added for clarity):
from typing import Callable
class event():
def __init__(self, condition: Callable[[], bool], outcome: str):
self.condition = condition
self.outcome = outcome
def check(self):
if self.condition():
print(self.outcome)
Then you'd use it by passing a callable that returns a bool when you call it; an easy way to do this inline is via a lambda:
foo = 0
e = event(lambda: foo != 0, "foo has changed value")
e.check()
foo = 1
e.check()

Python: Getting value from calling function

In Python, is there a simple way for an invoked function to get a value from the calling function/class ? I'm not sure if I'm phrasing that right, but I'm trying to do something like this:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass() # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
and
class secondClass(object):
def secondFunction(self, input)
output = input + self.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection
This might be my lack of knowledge about Python, but I'm having a hard time finding a clear answer here. Is the best way to do that just passing the variable I want in as another second parameter to the second class?
These are in separate files, if that makes a difference.
Is the best way to do that just passing the variable I want in as another second parameter to the second class?
Yes, especially if there's only a transient relationship between the objects:
class secondClass(object):
def secondFunction(self, input, var_from_caller)
output = input + var_from_caller # calculate value based on function parameter AND variable from calling function
return output
You can even pass around the whole object if you like:
class secondClass(object):
def secondFunction(self, input, calling_object)
output = input + calling_object.var # calculate value based on function parameter AND variable from calling function
return output
If the relationship is more permanent, you could consider storing references to the related objects in instance variables:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass(self) # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
...
class secondClass(object):
def __init__(self, my_friend):
self.related_object = my_friend
def secondFunction(self, input)
output = input + self.related_object.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection

__init__ with function as parameter (using the NetworkX)

The Question
I want to be able to initialize an object with a function that references the instance's attributes. What I want I tried to capture in this snippet, which produces a NameError: "global name 'self' is not defined":
class Test(object):
def __init__(self, function = None):
self.dicty = {1:{'height': 4, 'width': 2}, 2:{'height': 1, 'width': 2} }
if function == None:
self.function = lambda x : self.dicty[x]['height']
else:
self.function = function
if __name__ == '__main__':
def func1(x):
return self.dicty[x]['width']
def func2(x):
return self.dicty[x]['width']**2
G = Test(function = func1)
H = Test(function = func2)
I could solve the problem by creating a bunch of subclasses to Test, but that doesn't seem readable.
The Motivation
I am using NetworkX to do Python modeling and experiments. I was looking at the classic Albert-Barabasi Model and creating subclasses of the DiGraph class that included a Preference(self, node), Attachment(self, parent, child), and then a Grow(self, max_allowable_nodes). Instead of creating a whole bunch of subclasses like I mentioned before, I would love to be able to create an instance that modifies preference(). This would allow me to run numerical experiments without my code looking too much like Frankenstein. Looking forward to learning something new.
Edit:
Didn't know about the types class or the general idea of reflection. Obviously, still pretty new here. Really appreciate everyone answering my questions and pointing me in the right direction!
Given that the lambda you create in your __init__ refers to the instance (self), it looks like you want to attach a method to your instance, whereas here you're attaching a function. You need to create a method from the function and attach it to the instance:
import types
class Test(object):
def __init__(self, function = None):
self.dicty = {1:{'height': 4, 'width': 2}, 2:{'height': 1, 'width': 2} }
if function == None:
function = lambda self, x: self.dicty[x]['height']
self.function = types.MethodType(function, self)
A method is basically a function that is always passed the instance as the first argument, so you need to ensure any function you pass into your initialiser has self as the initial argument.
>>> t1 = Test()
>>> t1.function(1)
4
>>> t2 = Test(lambda self, x: self.dicty[x]['width'])
>>> t2.function(1)
2
When you define func1, there is no such thing as self. It's not an argument to the function, and it's not in any higher scope.
You could, instead, define a function that takes the dict you use as an argument and operates on that. In the Test class, you can then call the function on self.dicty. This would require you to change your lambda to also take dicty and x instead of just x.
def func1(dicty, x):
return dicty[x]['width']
...and in Test...
class Test(object):
# ... current code but with lambda tweak:
# lambda dicty, x: dicty[x]['height']
def do_something(self, x):
self.function(self.dicty, x)
Without seeing the rest of your code, it's hard to know what further simplifications you could make. But since all the functions seem to be using dicty[x] anyway, you could just write them to take that directly.

Categories

Resources