How to access class attributes within a class variable? - python

I want to reference a class attribute from class variable but it gives me error 'self is not defined'
class Test:
def __init__(self, val):
self.val = val
data = self.val
def main(self):
print(self.data)

When you say data = self.val outside __init__, you are defining a class variable, not an instance variable. This line affects all objects of type Test. However, self is not recognized in this scope.
If you want val to update all instances of this class,
class Test:
data = None
def __init__(self, val):
self.val = val
Test.data = self.val
In this case,
test1 = Test(1)
print(test1.data) # prints 1
print(Test.data) # prints 1
test2 = Test(2)
print(test1.data) # prints 2
print(test2.data) # prints 2
print(Test.data) # prints 2

Related

Python: How to rename public available variable?

Imagine having this class:
class Foo:
def __init__(self):
self.nr = 0
Imagine further Foo being widely used. Several scripts and users use the variable Foo.nr to read and write its value.
Now suppose the developer wants to change the name of .nr to .val.
class Foo:
def __init__(self):
self.val = 0
In order to not force the users to update their code, is it somehow possible to make them access .val by writing .nr? Like this:
f1 = Foo()
print(f1.nr)
I came up with properties and getter and setter methods but I don't see how they might help.
class Foo:
def __init__(self):
self.val = 0
#property
def nr(self):
return self.val
#nr.setter
def nr(self, value):
self.val = value
f1 = Foo()
print(f1.nr)
would give 0 as expected.

Issue with class variable in Python

I am new to python.I was doing following code and I met an undesired outcome. Please look onto my code and let me know what am I doing wrong:
class TestClass(object):
#classmethod
def __init__(self, val):
self.val = val
#classmethod
def value(self):
return self.val
def Test():
a = TestClass(9)
b = TestClass(8)
c = TestClass(7)
print(a.value(), b.value(), c.value())
expecting output as
9 8 7
but getting output as
7 7 7
what is wrong with my code.
Setting __init__ as a classmethod means you're actually passing the class to __init__ and self.val is actually set as a class variable, not an instance variable.
The final "initialization" you perform will override all the other values you've set.
Removing the #classmethods fixes the issue.
You have attached #classmethod to the __init__ function. As a result, if you call the __init__ (something you do at construction), self will not reference to the object you are about to construct, but to the class, so TestClass. Therefore there is only one value: attached to TestClass.
So TestClass(3) will be equivalent to something like TestClass.__init__(TestClass,3)...
You can solve the issue by removing the #classmethod decorator:
class TestClass(object):
def __init__(self, val): # no #classmethod
self.val = val
def value(self): # no #classmethod
return self.val
def Test():
a = TestClass(9)
b = TestClass(8)
c = TestClass(7)
print(a.value(), b.value(), c.value())
It is actually rather weird to use a #classmethod on an __init__ method. If you want to add attributes to the class, you can use type(..). So:
#classmethod
def __init__(cls, val):
cls.val = val
Is equivalent to:
def __init__(self, val):
type(self).val = val

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())

Descriptor class design in Python (with inheritance)

I'm trying to design a descriptor class which I can use through other class which is a subclass of a class which is a subclass of a class.
class MyDescriptorClass(object):
def __init__(self, owner, name, activates = 0):
self.value = None
self.name = name
self.owner = owner
self.activates = 0
self.connects = []
def __set__(self, obj, val):
self.set(val)
def __get__(self, instance, owner):
return self.value
def set(self, value):
if self.value == value:
return 0
self.value = value
if self.activates:
self.owner.evaluate()
def connect(self, inputs):
if not isinstance(inputs, list):
inputs = list(inputs)
for input in inputs:
self.connects.append(input)
class ParentClass(object):
def __init__(self, name):
self.states = {}
self.name = name
self.A = MyDescriptorClass(self, name, activates = 1)
self.B = MyDescriptorClass(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
class ChildClass1(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value + self.B.value
class ChildClass2(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value * self.B.value
self.A = MyDescriptorClass() will not work according to the python docs
so the only way is that I declate A = MyDescriptorClass() in the ParentClass as
class ParentClass(object):
A = MyDescriptorClass() # here I am unable to pass the owner
And since, I'm using a child class, super call skips this part and starts directly with __init__
Is there any way in which I can modify the design so as to set the value of ChildClass1.A instance directly?
c = ChildClass1("c1")
c.A = 10 # I directly want to set this value instead of using c.A.set(10)
c.B = 20
c.evaluate()
print c.ans # 30
c.B = 40
print c.ans # 50
Try not to put information which is specific to instances in the descriptor. Keep information specific to instances in instance attributes, and keep information specific to the descriptor (like activates) in the descriptor:
class MyDescriptorClass(object):
def __init__(self, activates = 0):
self.value = None
self.activates = activates
self.connects = []
def __set__(self, instance, val): # 1
if self.value == val:
return 0
self.value = val
if self.activates:
instance.evaluate()
def __get__(self, instance, instcls): # 1
return self.value
Note that the __set__ and __get__ methods are passed the
instance which is accessing the descriptor. Therefore, you do not
need to store the owner in MyDescriptor. The instance is the
owner.
Given the clarification of the problem in the comments below, here is how I would implement the descriptor.
class GateInput(object):
def __init__(self, index):
self.index = index # 4
def __get__(self, inst, instcls):
return inst.inputs[self.index].ans # 5
def __set__(self, inst, val):
if isinstance(val, (float, int)):
inst.inputs[self.index] = Constant(val)
else:
inst.inputs[self.index] = val
class Constant(object):
def __init__(self, val):
self.ans = val
class Gate(object):
A = GateInput(0) # 1
B = GateInput(1) # 1
def __init__(self, name):
self.name = name
self.inputs = [Constant(0), Constant(0)] # 2
class Adder(Gate):
#property
def ans(self):
result = 0
for gate in self.inputs:
result += gate.ans # 3
return result
class Multiplier(Gate):
#property
def ans(self):
result = 1
for gate in self.inputs:
result *= gate.ans
return result
b = Multiplier('b1')
b.A = 2
b.B = 3
print(b.A)
# 2
print(b.ans)
# 6
c = Adder('c1')
c.A = 10
print(c.ans)
# 10
# This connects output of b to an input of c
c.B = b
print(c.ans)
# 16
Descriptors have to be defined as class attributes, not instance
attributes. Since the descriptor is accessed by all instances, you
probably do not want the descriptor to change merely because an
instance is being created. Therefore, do not instantiate the
descriptor in __init__.
Each instance of Gate has a list of inputs. The items self.inputs
are instances of Constant or Gate.
Here we see the purpose of the Constant class. For every gate,
gate.ans needs to return a value.
The index records which item in inst.inputs the GateInput is
connected to.
inst is an instance of Gate. For example, c.A causes Python to
call GateInput.__get__(self, c, type(c)). Thus, inst is c
here.
As it is int he comments:
descriptors must be class attributes, not instance attributes in order to work -
so, to start with:
class ParentClass(object):
A = MyDescriptorClass()
B = MyDescriptorClass()
def __init__(self, name):
self.states = {}
self.name = name
self.A.configure(self, name, activates = 1)
self.B.configure(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
And then you fix your Descriptor class accordingly:
either have then keeping all data refering to an instance in the instance itself
(that is why __get__ and __set__ receive the object itself) - or have
each descriptor instance have a dictionary where they can annotate data related
to the instances of the class they belong too, by, for example, object ID.
Your descriptor class could be more or less along these lines:
class MyDescriptorClass(object):
def __init__(self):
self.data = defaultDict(dict)
def configure(self, owner, name, activates = 0):
container = self.data(id(owner))
container["value"] = None
container["name"] = name
...
def __set__(self, owner, value):
# implemnt your previous "set" method straight here
...
...

Categories

Resources