Usage of self inside instance methods in Python - python

I have a class like this
class Test:
def __init__(self, var):
self.var = var
def test(self):
x = self.var + 2
return x
And then I make a class like this
class Test:
def __init__(self, var):
self.var = var
def test(self):
self.x = self.var + 2
return self.x
I understand that I can use self to separate attribute values across various instances of this class. My question is, if I create many utility variables (like x) inside a method, should I always create them using self?
Can anyone explain how the above two classes behave differently (if they do)?

Let's see the difference between the two classes :
class Test:
def __init__(self, var):
self.var = var
def test(self):
x = self.var + 2
return x
Let's create a Test object:
t = Test(1)
And see what we can do
t.var # 1
t.x # Raises AttributeError : no such attribute in the class
t.test() #3
t.x # Still erroring
And with your second class
class Test:
def __init__(self, var):
self.var = var
def test(self):
self.x = self.var + 2
return self.x
Let's create a Test object:
t = Test(1)
And see what we can do
t.var # 1
t.x # Raises AttributeError : no such attribute in the class
t.test() #3
t.x # 3
So what ? Well we can see that any variables defined with self.VARNAME persist in the instance, while simple local variables, without self., dosen't.
However, if x needs to be accessible with t.x, i'd probably go for a property, like so
class Test:
def __init__(self, var):
self.var = var
#property
def x(self):
x = self.var + 2
return x
t = Test()
t.x # 3

Related

How to use properties and setters the Pythonic way

I'm following this code example from a python course:
class P:
def __init__(self,x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
And I tried to implement this pattern to my own code:
class PCAModel(object):
def __init__(self):
self.M_inv = None
#property
def M_inv(self):
return self.__M_inv
#M_inv.setter
def set_M_inv(self):
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
self.__M_inv = np.linalg.inv(M)
Note that I want the M_inv property to be None before I have run the setter the first time. Also, the setter solely relies on other properties of the class object, and not on input arguments.
The setter decorator generates an error:
NameError: name 'M_inv' is not defined
Why is this?
Your setter method should be like below:
#M_inv.setter
def M_inv(self):
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
self.__M_inv = np.linalg.inv(M)
The decorator #M_inv.setter and the function def M_inv(self): name should be same
The example is wrong.
EDIT: Example was using a setter in __init__ on purpose.
Getters and setters, even though they act like properties, are just methods that access a private attribute. That attribute must exist.
In the example, self.__x is never created.
Here is my suggested use :
class PCAModel(object):
def __init__(self):
# We create a private variable
self.__M_inv = None
#property
def M_inv(self):
# Accessing M_inv returns the value of the previously created variable
return self.__M_inv
#M_inv.setter
def M_inv(self): # Keep the same name than your propery
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
self.__M_inv = np.linalg.inv(M)

Why can't #var.setter function access class variables?

I have a class where I want to validate the data whenever it's property is changed. I wish to store the valid options as a class variable that the setter can refer to, but I seem to have found that within the #var.setter option I'm unable to reference any class variables at all.
Why is that?
Code example:
class Standard():
def __init__(self):
self.variable1 = 1
self.variable2 = 2
#property
def variable1(self):
# This works
print(self.variable2)
return self.__variable1
#variable1.setter
def variable1(self, var):
# This doesn't work
print(self.variable2)
self.__variable1 = var
x = Standard()
print(x.variable1)
x.variable1 = 4
print(x.variable1)
This outputs:
AttributeError: 'Standard' object has no attribute 'variable2'
When it clearly does.
You are first setting variable1 in __init__:
def __init__(self):
self.variable1 = 1
self.variable2 = 2
Since self.variable1 is handled by #variable1.setter, variable2 can't yet exist at that time. You could swap the two lines:
def __init__(self):
self.variable2 = 2
self.variable1 = 1
Now variable2 is properly set before variable1.setter runs.
Alternatively, give variable2 a class attribute to act as a default:
class Standard():
# ...
variable2 = 'class default'
#variable1.setter
def variable1(self, var):
print(self.variable2)
self.__variable1 = var
or use getattr() on self:
#variable1.setter
def variable1(self, var):
print(getattr(self, 'variable2', 'not available yet'))
self.__variable1 = var
or set __variable1 directly, bypassing the setter:
class Standard():
def __init__(self):
self.__variable1 = 1 # don't use the setter
self.variable2 = 2

Newbie Debugging a Python Code

I want local variable of a class to be changed by other class. My script is similar to the following :
import datetime
b = []
class P:
def __init__(self):
self.count = 1
self.create()
def create(self):
global b
a = C(self.count)
for i in range(10):
a.print_name()
print b
class C:
def __init__(self, *data):
self.test = data[0]
#staticmethod
def print_name():
global b
b.append(datetime.datetime.now())
o = P()
How to avoid use of a global variable . On web i found use of "super " can resolve the issue . Please help in this regard .
Make C constructor to accept P instance. And call the method of P to append item to instance attribute of P object.
class P:
def __init__(self):
self.count = 1
self.items = []
self.create()
def append(self, item):
self.items.append(item)
def create(self):
a = C(self, self.count) # <-- Pass P instance (self)
for i in range(10):
a.print_name()
print self.items
class C:
def __init__(self, p_instance, *data):
self.p_instance = p_instance # <-- Save P instance to use later
self.test = data[0]
def print_name(self):
self.p_instance.append(datetime.datetime.now()) # <-- Call p instance method
You are probably looking for a class attribute. If you add b as an attribute to the C class, it can be accessed as C.b and C().b, i.e. from a reference to the class or any instance.
class C(object): # classes in py2 should inherit from object!
b = [] # b inside C definition
#classmethod
def print_name(cls):
cls.b.append(datetime.datetime.now())
class P(object):
def __init__(self):
self.count = 1
self.create()
def create(self):
a = C(self.count)
for i in range(10):
a.print_name()
print C.b # or a.b
Of course, you can also place b on P. In this case, do
def print_name():
P.b.append(datetime.datetime.now())

Python3.4: unable to access the variables in the method which is definded in the same class

Have written a simple code like this:
class Operations:
#global a,b
a=1
b=2
def __init__(self):
print(self,"object has been created")
def add(self):
#a = 2
#b = 3
return a+b
obj1=Operations()
sum=obj1.add()
print(sum).
when i run this code, am getting this error NameError: name 'a' is not defined.
can you please explain why variables a and b are not accessible in the method 'add' which is defined in the same class?
Note:when am declaring variables as a global, am able to access the variables inside the 'add' method.
You need to use the self keyword.
What does self do?
a = 1
class Operations:
a = 2
def fun1(self):
return a
def fun2(self):
return self.a
obj = Operations()
print(obj.fun1())
print(obj.fun2())
Output:
1
2
Solution for you case:
class Operations:
a=1
b=2
def __init__(self):
print(self,"object has been created")
def add(self):
return self.a + self.b
obj1=Operations()
print(obj1.add())
Output:
<__main__.Operations object at 0x100663588> object has been created
3
Use the class reference
Value= self.a + self.b
Is this the answer that you need? if you're writing a class, use self.value instead global value:
class Operations:
def __init__(self):
self.a = 1
self.b = 2
print(self, "object has been created")
def add(self):
return self.a + self.b
obj1 = Operations()
print(obj1.add())

Composition - Reference to another class in Python

In my example below in Python, object x 'has-an' object y. I'd like to be able to invoke methods of x from y.
I'm able to achieve it using #staticmethod, however I'm discouraged to do that.
Is there any way(s) to reference the whole Object x from Object y?
class X(object):
def __init__(self):
self.count = 5
self.y = Y() #instance of Y created.
def add2(self):
self.count += 2
class Y(object):
def modify(self):
#from here, I wanna called add2 method of object(x)
x = X()
print x.count
>>> 5
x.y.modify()
print x.count
>>> # it will print 7 (x.count=7)
Thanks in advance.
You need to store a reference to the object which has the instance of a Y object:
class X(object):
def __init__(self):
self.count = 5
self.y = Y(self) #create a y passing in the current instance of x
def add2(self):
self.count += 2
class Y(object):
def __init__(self,parent):
self.parent = parent #set the parent attribute to a reference to the X which has it
def modify(self):
self.parent.add2()
Example usage:
>>> x = X()
>>> x.y.modify()
>>> x.count
7
Maybe it's possible for you to use class inheritance? For example:
class X(object):
def __init__(self):
self.count = 5
def add2(self):
self.count += 2
class Y(X):
def __init__(self):
super(Y, self).__init__()
def modify(self):
self.add2()
y = Y() # We now create an instance of Y which is a child class of 'super' class X
y.modify()
print(y.count) # 7

Categories

Resources