How to use self in instance variable in python - python

Its possibly a very silly question and I just do not know how to look for this solution or what to search.
What I was trying is
class X:
def __init__(self, myvariable):
self.myvariable = myvariable
def printVar(self):
print(self.myvariable)
class Z:
aa = 'test'
class Y(Z):
#xx = X(self.aa)
def __init__(self):
self.xx = X(self.aa)
x = Y()
x.xx.printVar()
it works as expected. I was wondering whether its possible to use as
class Y(Z):
xx = X(self.aa)

self only refer to the own context of a class.
You can refer to aa with Z.aa:
class Y(Z):
xx = X(Z.aa)
print(Z.aa)
->
test

Related

How to preserve the value of class properties

class A:
p = 1
def __init__(self, p=None, **kwargs):
self.p = p
class B(A):
p = 2
a = A()
print(a.p)
b = B()
print(b.p)
As a more sensible example consider:
class Mamal:
can_fly = False
class Bat(Mamal):
can_fly = True
In the examples above, I would like 1 and 2 be printed. However, it prints None for both, though I know why. What is the solution to preserve the default value of classes?
One solution I can think of is:
class A:
p = 1
def __init__(self, p=None, **kwargs):
if p: self.p = p
if q: self.q = q
...
and if I have many attributes I should do that for all of them!? another minor problem is that the user can't pass None to the class init.
Another solution could be like:
class A:
p = 1
def __init__(self, p=1, **kwargs):
self.p = p
self.q = q
...
However again if one instantiate b like:
b = B()
the value of b.p would be also 1, while I expect it to keep 2.
I use overriding classes attributes much, but I just don't know how to preserve them from being overwritten by default values of the same or parent class.
Yet, another solution is combination of the above, like:
class A:
p = 1
def __init__(self, p=1, **kwargs):
if p != 1: self.p = p
...
or using dataclass
from dataclasses import dataclass
#dataclass
class A:
p :int = 1
#dataclass
class B(A):
p:int = 2
Just would like to know what is usual approach and consequences.
UPDATE:
If you really absolutely need both your class and your instances to have this attribute, and also want to use the class attribute as the default for an instance, I would say the correct way is like this:
_sentinel = object()
class A:
p = 1
def __init__(self, p=_sentinel):
if p is not _sentinel:
self.p = p
class B(A):
p = 2
a = A()
print(a.p) # prints 1
b = B()
print(b.p) # prints 2
b2 = B(p=None)
print(b2.p) # prints None
The sentinel object is for when you do want to be able to pass None to the constructor for whatever reason. Since we compare identity in the __init__ method, it is (practically) guaranteed that if any value is passed, it will be assigned to the instance attribute, even if that value is None.
Original answer:
The problem seems to stem from a misunderstanding of how (class-)attribute work in Python.
When you do this:
class A:
p = 1
You define a class attribute. Instances of that class will automatically have that same attribute upon initialization, unless you overwrite it, which is exactly what you do here:
def __init__(self, p=None, **kwargs):
self.p = p
This overwrites the instance's attribute .p with the value p it receives in the __init__ method. In this case, since you defined a default value None and called the constructor without passing an argument, that is what was assigned to the instance's attribute.
If you want, you can simply omit the self.p assignment in the constructor. Then your instances will have the class' default upon initialization.
EDIT:
Depending on how you want to handle it, you can simply assign the value after initialization. But I doubt that is what you want. You probably don't need class attributes at all. Instead you may just want to define the default values in your __init__ method signature and assign them there.
If you really need that class attribute as well, you can do what you did, but more precisely by testing for if p is not None:.
I would set the default value of the p argument to the value that you want:
class A:
def __init__(self, p=1, **kwargs):
self.p = p
class B(A):
def __init__(self, p=2, **kwargs):
super().__init__(p, **kwargs)
a = A()
print(a.p)
b = B()
print(b.p)
Then from the constructor of B you can call the one from A by using super().__init__
You can use class properties from the class:
class A:
p = 1
class B(A):
p = 2
a = A()
print(a.p)
b = B()
print(b.p)
prints 1 and 2, like you wanted.
It is clearer to access them from the class directly, though:
print(A.p)
print(B.p)
You can set the instance one, without changing what is associated in the class.
class B(A):
def change(self, x):
self.p = x
b.change(3)
print(B.p) #2
print(b.p) #3

Python Variables across Class functions - how to call them?

Instead of using a global variable, I'm trying to make an instance of a variable in a class, as it seems to be best practice. How do I reference this variable across other functions in the class? I would have thought that Test.running_sum would work or at least running_sum in test_function, but I'm not having any luck with either. Thanks very much!
class Test:
def __init__(self):
self.root = None
running_sum = 0
def test_function(self):
print(Test.running_sum)
return
x = Test()
x.test_function()
Error:
Traceback (most recent call last):
File "so.py", line 1, in <module>
class Test:
File "so.py", line 10, in Test
x = Test()
NameError: name 'Test' is not defined
Use self parameter provided in the method signature.
Note that what you wrote is not a method, but an external function using class Test. To write a method of Test, the def should be at one level of indentation inside class Test as following:
class Test:
def __init__(self):
self.running_sum = 0
def test_function(self):
print(self.running_sum)
There are several things to add if you want an explanation behind this "best practice".
Assuming you write the following code:
class Test:
numbers = []
def add(self, value):
self.numbers.append(value)
The Test.numbers list is instantiated once and shared accross all instances of Test. Therefore, if 2 different instances add to the list, both act on the same list:
a = Test()
b = Test()
a.add(5)
b.add(10)
assert a.numbers == b.numbers == Test.numbers
When creating instance variables in the __init__ function, __init__ will be run at each instantiation, and therefore, the list will no longer be shared because they will be created for each individual instances.
class Test:
def __init__(self):
self.numbers = []
def add(self, number):
self.numbers.append(number)
a = Test()
b = Test()
a.add(5)
b.add(10)
assert a != b
As an object attribute: each object gets its own.
Test is the class; self is the Test object that invoked the method.
class Test:
def __init__(self):
self.root = None
self.running_sum = 0
def test_function(self):
self.running_sum += 1
print(self.running_sum)
return
x = Test()
y = Test()
x.test_function()
y.test_function()
Output:
1
1
As a class attribute: all objects share the same variable.
self.__class__ is the class of the invoking object (i.e. Test).
class Test:
running_sum = 0
def __init__(self):
self.root = None
def test_function(self):
self.__class__.running_sum += 1
print(self.__class__.running_sum)
return
x = Test()
y = Test()
x.test_function()
y.test_function()
Output:
1
2
how do I reference this variable across other functions in the class
Several things I see wrong here. First of all, you are calling running_sum on the class itself which doesn't make sense since you are declaring running_sum as an attribute of an instance of Test. Second, from the way you formatted your question, it seems that test_function is outside of the class Test which doesn't make sense since you are passing self to it, implying it is an instance method. To resolve you could do this:
class Test:
def __init__(self):
self.running_sum = 0
def test_function(self):
print(self.running_sum)
Then again this also is weird... Why would you need a "test_function" when you can simply test the value of running_sum by simply doing:
x = Test()
x.running_sum
In your __init__ function, you've created a local variable. That variable will no longer exist after the function has completed.
If you want to create a variable specific to the object x then you should create a self.running_sum variable
class Test:
def __init__(self):
self.root = None
self.running_sum = 0
def test_function(self):
print(self.running_sum)
If you want to create a variable specific to the class Test then you should create a Test.running_sum variable.
class Test:
running_sum = 0
def __init__(self):
self.root = None
def test_function(self):
print(Test.running_sum)

confused value scope in python

Hi I have staring programming with c and I conld'nt understand value scope in python.
here is my code
class ScenarioEnvironment():
def __init__(self):
print(self)
class report():
config = ScenarioEnvironment()
def __init__(self):
self.config = ScenarioEnvironment()
what happens passing config and config at init()?
and I wonder the value scope which config will be class valuable?
You need to know the differences between class attribute and instance object attribute.
Maybe these codes will help you:
class TestConfig1(object):
config = 1
def __init__(self):
self.config = 2
class TestConfig2(object):
config = 1
def __init__(self):
self.config2 = 2
if __name__ == "__main__":
print TestConfig1.config
t = TestConfig1()
print t.config
t2 = TestConfig2()
print t2.config
print t2.config2
more you can see the python blog.click here
Since your question seems a bit ambiguous, I'll just comment/fix your code:
class ScenarioEnvironment():
def __init__(self,x):
self.x = x # Assigning instance variable x to constructor parameter x.
print(self) # You're printing the object instance.
class report():
# Static variable shared amongst all classes.
config = ScenarioEnvironment(None) # Assigned to new instance of ScenarioEnvironment.
def __init__(self):
# No argument, must pass one (None).
# self.config is to a new ScenarioEnvironment instance.
self.config = ScenarioEnvironment(None)
Lets try out the classes.
Output:
s = ScenarioEnvironment(None)
r = report()
>>> <__main__.ScenarioEnvironment instance at 0x026F4238>
>>> <__main__.ScenarioEnvironment instance at 0x026F4300>
>>> <__main__.ScenarioEnvironment instance at 0x026F4350>

Best way to create objects with objects inside

I need to create a system of objects which in turn have objects inside, for example:
class A(object):
def __init__(self):
self.A = 'Message from class A'
class B(object):
def __init__(self):
self.B = A()
or do it in this way
class B(object):
def __init__(self):
self.B = A()
class A(object):
def __init__(self):
self.A = 'Message from class A'
so I can't use it like
>>> C = B()
>>> print C.B.A
# Message from class A
what is the best choice of these two, or if there is something else, please welcome!
EDIT 1 current piece of code
class Foam(object):
def __init__(self, rotor, path='OpenFoamCase'):
self.dirs = {}
self.path = path
self.rotor = rotor
self.rotorObj = Rotor(rotor)
# OpenFoam case directories
self.dirs['main'] = path if path.endswith('/') else path + '/'
self.dirs['system'] = path + '/system/'
self.dirs['constant'] = path + '/constant/'
self.dirs['geometry'] = path + '/geometry/'
self.dirs['polyMesh'] = path + '/constant/polyMesh/'
self.dirs['triSurface'] = path + '/constant/triSurface/'
self.__openFoamInit()
self.mesh = OpenFoamBlockMesh(self)
class OpenFoamBlockMesh(object):
def __init__(self, study):
self.airfoil_offset = 0.5
self.rotor_disk_length = [20, 20]
...
def box(self):
...
so now I’m using it as:
study = Foam(rotor=rotor, path='OpenFoamCase_Tesis')
study.mesh.airfoil_offset = 0.02
study.mesh.rotor_disk_length = [2, 2.5]
study.mesh.box()
It really depends on your purpose. If the A class is just a helper class for B, and is a simple and small class, you can use the second method (inner class).
If the class A, might be used for others classes or is a big class, is recommended to use the first method (simple composition).
If you provide a better example of your real world problem, we may be able to help you more.

Creating an object with a reference to the object that created it

I have a program where an object creates another object. However, the second object that gets created needs to be able to access the first. Is this possible?
EG (pseudocode)
class parentObject():
parentVar = 1
# Create Child
x = childObject()
class childObject():
#Assign Var to the Var of the childs parent
childVar = parent.parentVar
>>> x.childVar = 1
is there a straitforward way to do this?
UPDATE:
I don't want to inheret the class, I need to be able to access the actual object that created it, as each object created from that class has different values.
Why not inherit the class?
class parentObject():
parentVar = 1
class childObject(parentObject):
childVar = parentObject.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you are going to have different instances of the class, you should do it as this instead:
class parentObject(object):
def __init__(self):
self.parentVar = 1
class childObject(parentObject):
def __init__(self):
super(childObject, self).__init__()
self.childVar = self.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you want a reference to the "parent" class, but inheritance is illogical, consider sending self in to the constructor:
class Room:
def __init__(self, name):
self.name = name
self.furniture = []
def add_chair(self):
self.furniture.append(Chair(self))
def __str__(self):
return '{} with {}'.format(self.name, self.furniture)
class Chair:
def __init__(self, room):
self.room = room
def __str__(self):
return 'Chair in {}'.format(self.room.name)
r = Room('Kitchen')
r.add_chair()
r.add_chair()
print r
print r.furniture[0]
Output:
Kitchen with [<__main__.Chair instance at 0x01F45F58>, <__main__.Chair instance at 0x01F45F80>]
Chair in Kitchen

Categories

Resources