Static variable inheritance in Python - python

I'm writing Python scripts for Blender for a project, but I'm pretty new to the language. Something I am confused about is the usage of static variables. Here is the piece of code I am currently working on:
class panelToggle(bpy.types.Operator):
active = False
def invoke(self, context, event):
self.active = not self.active
return{'FINISHED'}
class OBJECT_OT_openConstraintPanel(panelToggle):
bl_label = "openConstraintPanel"
bl_idname = "openConstraintPanel"
The idea is that the second class should inherit the active variable and the invoke method from the first, so that calling OBJECT_OT_openConstraintPanel.invoke() changes OBJECT_OT_openConstraintPanel.active. Using self as I did above won't work however, and neither does using panelToggle instead. Any idea of how I go about this?

use type(self) for access to class attributes
>>> class A(object):
var = 2
def write(self):
print type(self).var
>>> class B(A):
pass
>>> B().write()
2
>>> B.var = 3
>>> B().write()
3
>>> A().write()
2

You can access active through the class it belongs to:
if panelToggle.active:
# do something
If you want to access the class variable from a method, you could write:
def am_i_active(self):
""" This method will access the right *class* variable by
looking at its own class type first.
"""
if self.__class__.active:
print 'Yes, sir!'
else:
print 'Nope.'
A working example can be found here: http://gist.github.com/522619
The self variable (named self by convention) is the current instance of the class, implicitly passed but explicitely recieved.
class A(object):
answer = 42
def add(self, a, b):
""" ``self`` is received explicitely. """
return A.answer + a + b
a = A()
print a.add(1, 2) # ``The instance -- ``a`` -- is passed implicitely.``
# => 45
print a.answer
# => print 42

Related

Monkey patching class functions and properties with an existing instance in Jupyter

When I'm prototyping a new project on Jupyter, I sometimes find that I want to add/delete methods to an instance. For example:
class A(object):
def __init__(self):
# some time-consuming function
def keep_this_fxn(self):
return 'hi'
a = A()
## but now I want to make A -> A_new
class A_new(object):
def __init__(self, v):
# some time-consuming function
self._new_prop = v
def keep_this_fxn(self):
return 'hi'
#property
def new_prop(self):
return self._new_prop
def new_fxn(self):
return 'hey'
Without having to manually do A.new_fxn = A_new.new_fxn or reinitializing the instance, is it possible to have this change done automatically? Something like
def update_instance(a, A_new)
# what's here?
a = update_instance(a, A_new(5)) ## should not be as slow as original initialization!
>>> type(a) ## keeps the name, preferably!
<A>
>>> a.keep_this_fxn() ## same as the original
'hi'
>>> a.new_fxn(). ## but with new functions
'hey'
>>> a.new_prop ## and new properties
5
Related posts don't seem to cover this, especially new properties and new args:
How to update instance of class after class method addition?
Monkey patching class and instance in Python
Here's my current attempt:
def update_class_instance(instance, NewClass, new_method_list):
OrigClass = type(instance).__mro__[0]
for method in new_method_list:
setattr(OrigClass, method, getattr(NewClass, method))
but (a) I still have to specify new_method_list (which I prefer to be handled automatically if possible, and (b) I have no idea what to do about the new properties and args.

correct way to return variables as arguments to method

A noob confused question,
I have two methods in a class as :
from example import sample2
class sample1:
def m1():
a='apple'
b='ball'
return sample2.m3(a,b)
def m2():
a='ant'
b='bat'
c='cat'
return sample2.m3(a,b,c)
in example.py:
class sample2:
def m3("here I want to access any `a`,`b`,`c` of respective m1 and m2"):
.....
Iam sorry if this question makes no sense, but when I try to access only this as:
class sample1:
def m1():
a='apple'
b='ball'
return sample2.m3(a,b)
in example.py:
class sample2:
def m3(a,b):
print(a)
a has value apple, so similar way why can't I access any value of a,b,c from that particular m1,m2 returned ?
This is how you use decorators. More information how decorator works can be found in for example here: https://www.datacamp.com/community/tutorials/decorators-python
I would suggest you to first try to better understand concept of class and objects. Example tutorial: https://www.w3schools.com/python/python_classes.asp
This post could also help you to understand how staticmethod decorator works - What is the difference between #staticmethod and #classmethod?
from example import sample2
class sample1:
#staticmethod
def m1():
a='apple'
b='ball'
return sample2.m3(a,b)
#staticmethod
def m2():
a='ant'
b='bat'
c='cat'
return sample2.m3(a,b,c)
example.py file with explanation:
class sample2:
#staticmethod
def m3(a, b, c=None): # it works exactly the same as m3 function that is outside the class
print(a)
# this can be used without creating an object of sample2 class, example:
# sample2.m3(a="apple, b="ball")
def m3_method(self, a, b): # this one requires object on which it can be called
print(a)
# you have access to sample2 class object via self parameter, example of code:
# sample2_object = sample2() # you create object of sample2 class here
# sample2_object.m3_method(a="apple", b="ball") # you call m3_method on sample2_object here
def m3(a, b, c=None): # default value of c is add so you can either call it with 2 or 3 arguments
# example calls:
# m3("a", "b")
# m3("a", "b", "c")
print(a)
You should be able to run this code and I think it gives you an idea how Python classes can be used.
Variables in Python always apply to a specific scope, such as a class, function or closure. Python uses lexical scoping, which means scopes are only connected by nesting in the source code. Most importantly, variables in different scopes are not connected at all.
When you "pass a variable" to a function, you are actually passing only the value around. The variable does not exist in other functions (unless they are nested) nor the surrounding scope.
def nested(a):
a = 3
print('a =', a) # a = 3
def parent():
a = 4
nested(a)
print('a =', a) # a = 4
parent()
print(a) # NameError: name 'a' is not defined
Functions should primarily exchange data by calling with input and returning results:
def nested(a): # receive input
a = 3
print('a =', a) # a = 3
return a # return output
def parent():
a = 4
a = nested(a) # replace a with result of nested(a)
print('a =', a) # a = 3
parent()
Note that only values are passed in and returned. The above could would behave exactly the same if you renamed a in either function.
When working with class instances, the instance itself works as a namespace (similar to a scope). Methods of that instance can exchange data by modifying attributes of the instance. The instance is always passed as the first argument to methods:
class Example():
"""An example for setting attributes on an instance"""
def __init__(self):
self.a = 0
def nested(self):
self.a = 3
print('self.a =', self.a) # self.a = 3
def parent(self):
self.a = 4
print('self.a =', self.a) # self.a = 4
self._nested()
print('self.a =', self.a) # self.a = 3
instance = Example()
print(instance.a) # 0
instance.parent() # self.a = 4
# self.a = 3
To exchange data between objects, methods should also primarily exchange data by calling with input and returning results :
class Example():
"""An example for setting attributes on an instance"""
def __init__(self, a):
self.a = a
def multiply(self, value):
return self.a * value
instance = Example(6)
print(instance.multiply(10)) # 60

How to get object attributes to update dynamically in Python

I'd like to create a class that has 2 input attributes and 1 output attribute such that whenever one of the input attributes are modified the output attribute is modified automatically
I've tried defining the attributes as instance variables within and outside the constructor function but in either case, after instantiating the object, the output attribute remains fixed at the value set at the moment of instantiation
class Example():
def __init__(self,n):
self.name=n
inA=1
inB=1
if inA==1 and inB==1:
outA=1
else:
outA=0
when instantiated outA is set to 1 as expected
but if I try to update:
object.inA=0
object.outA remains 1 whereas I need it to be updated to 0
Trying to avoid the use of functions if possible. New to python and OOP so sorry if this question is nonsensical or has an obvious answer
If you want instance attributes that depend on other instance attributes, properties are the way to go.
class Example:
def __init__(self, n):
self.name = n
self.inA = 1
self.inB = 1
#property
def outA(self):
return self.inA and self.inB
You access outA like a regular instance attribute, obj.outA.
>>> my_obj = Example("example")
>>> my_obj.outA
1
Changing the attributes inA and inB affect outA.
>>> my_obj.inA = 0
>>> my_obj.outA
0
You can create a function in the class and some other minor changes:
class Example():
def __init__(self,n):
self.name=n
self.inA=1
self.inB=1
def f(self):
if self.inA==1 and self.inB==1:
self.outA=1
else:
self.outA=0
To call it:
a = Example('foo')
a.inA = 0
a.f()
print(a.outA)
Output:
0
As you can see, taking out:
a.f()
line would make it give an error:
AttributeError: 'Example' object has no attribute 'outA'
Do you want it to return your output?
Expanding on U9-Forward's answer:
class Example():
def __init__(self,n):
self.name = n
self.inA = 1
self.inB = 1
def f(self):
return self.inA and self.inB

Creating methods on the fly for a class instance

The following program is unable to create a function of a class
class MyClass(object):
def __init__(self, name=""):
self.name = name
def read_name(self):
return self.name
# First argument should be a ref to class
def callback(fcn, arg):
fcn.name=arg
# Create a instance of class
a = MyClass("Blue")
# Lets add new member functions
setattr(a, 'callback1', callback)
setattr(a, 'callback2', callback)
print a.read_name()
print a.callback1("purple") #! FAILS
print a.callback2("cyan") #! FAILS
What is the right way of creating a class member function automatically?
I want to create 'N' callback functions, they all will modify some common/uncommon class data (A shared dict)
EDIT 1
I wish to collect information from 'N' separate/parallel threads by passing callback functions. I do not know beforehand how many callback functions I need thus I want to create them on fly.
EDIT 2
I have a dictionary(d) where I am storing the information of different processes. The dictionary(d) is accessed within the callback. But because the same callback function is called at different threads, the dictionary data gets garbled. As a quickfix, I thought of creating separate callbacks.
If you know what you're doing, you'd want to try
import types
setattr(a, 'callback1', types.MethodType(callback, a, MyClass))
In short: when grafting a method, assign it to the class, not to the instance.
Here's an elucidating example.
class A(object):
"""As trivial as a class can get."""
def foo(self):
return self.bar(1) + self.baz()
# Rework everything!
def new_bar(self, x):
return 'I got %r' % x
def new_baz(self):
return ' and I\'m okay!'
A.bar = new_bar
A.baz = new_baz
print A().foo()
Now grafting method to an instance.
a = A()
# An instance attribute is a bound method;
# when we replace it with a function, we lose access to self.
a.bar = lambda x: x * 100
A.baz = lambda self: 42
assert a.foo() == 142
# We can do better, though.
from types import MethodType
a2 = A()
a2.foo = MethodType(lambda self: 'I know myself, my class is %s' % self.__class__.__name__, a2)
print a2.foo()
Note how you don't need setattr to set an attribute, even an unknown attribute. You may remember that you don't use setattr in __init__ either.
You can't add a class method to an instance; you have to add it to the class:
setattr(MyClass, 'callback1', callback)
But it's still a terrible idea. Why would you want this functionality?
Edit: keep your callbacks in a container instead:
class MyClass(object):
def __init__(self, name=""):
self.name = name
self.callbacks = []
def callback(self, idx, arg):
self.callbacks[idx](self, arg)
# First argument should be a ref to class
def callback(fcn, arg):
fcn.name=arg
# Create a instance of class
a = MyClass("Blue")
# Lets add new member functions
a.callbacks.append(callback)
a.callbacks.append(callback)
print a.name
a.callback(0, "purple")
print a.name
a.callback(1, "cyan")
print a.name

In a Python class, what is the difference between creating a variable with the self syntax, and creating one without ?

What is the difference between creating a variable using the self.variable syntax and creating one without?
I was testing it out and I can still access both from an instance:
class TestClass(object):
j = 10
def __init__(self):
self.i = 20
if __name__ == '__main__':
testInstance = TestClass()
print testInstance.i
print testInstance.j
However, if I swap the location of the self, it results in an error.
class TestClass(object):
self.j = 10
def __init__(self):
i = 20
if __name__ == '__main__':
testInstance = TestClass()
print testInstance.i
print testInstance.j
>>NameError: name 'self' is not defined
So I gather that self has a special role in initialization.. but, I just don't quite get what it is.
self refers to the current instance of the class. If you declare a variable outside of a function body, you're referring to the class itself, not an instance, and thus all instances of the class will share the same value for that attribute.
In addition, variables declared as part of the class (rather than part of an instance) can be accessed as part of the class itself:
class Foo(object):
a = 1
one = Foo()
two = Foo()
Foo.a = 3
Since this value is class-wide, not only can you read it directly from the class:
print Foo.a # prints 3
But it will also change the value for every instance of the class:
print one.a # prints 3
print two.a # prints 3
Note, however, that this is only the case if you don't override a class variable with an instance variable. For instance, if you created the following:
class Bar(object)
a = 1
def __init__(self):
self.a = 2
and then did the following:
one = Bar()
two = Bar()
two.a = 3
Then you'd get the following results:
print Bar.a # prints "1"
print one.a # prints "2"
print two.a # prints "3"
As noted in the comments, assigning to two.a creates an instance-local entry on that instance, which overrides the a from Bar, hence why Bar.a is still 1 but two.a is 3.
j is a class variable as pointed by Amber. Now, if you come from C++ background, self is akin to the this pointer. While python doesn't deal with pointers, self plays the similar role of referring to current instance of the class.
In the python way, explicit is better than implicit. In C++, the availability of this is conventionally assumed for each class. Python, on the other hand, explicitly passes self as first argument to each of your instance methods.
Hence self is available only inside the scope of your instance methods, making it undefined for the place from which you tried using it.
Since you're made to explicitly pass self to instance methods, you could also call it something else if you want to -
>>> class Foo:
... b = 20
... def __init__(them):
... them.beep = "weee"
...
>>> f = Foo()
>>> f.beep
'weee'

Categories