change class instance attribute conditionally in python - python

I'm a newbie in python. I have a class X inheriting class Y. In class X the attribute b allways
keep constant and never change but in the class Y it must change when a given
condition is satisfied.
class X(object):
def __init__(self,others_attributes):
self.b = 1
self.others_attributes = others_attributes
class Y(X):
def __init__(self,others_attributes,variable_condition):
super(X, self).__init__(others_attributes)
self.b += 1
How can ensure that each simulation step any instance of the class Y will have a specific value of the attribute b? Shall I create a #classmethod or a #properties similar to something like below?
Or is there a better strategy?
if variable_condition:
self.b = self.b + 1
else:
self.b = self.b
return self.b

Not sure if you're asking about maintaining class level state or instance level state.
If you're asking about how to change class level state all you need to do is store b as a class variable:
some_condition = True
class X(object):
count = 0
class Y(X):
def __init__(self):
if some_condition:
Y.count += 1
instances = [
X(),
Y(),
Y(),
X(),
X(),
Y()
]
print('\n'.join([str(i.count) for i in instances]))
If you want to change the b for only certain instances of Y then you could do something like:
class X(object):
def __init__(self):
self.b = 0
class Y(X):
def __init__(self, some_condition):
super(Y, self).__init__()
if some_condition:
self.b += 1 # or set it to whatever else you want
else:
self.b = -1
instances = [
X(),
Y(True),
Y(False),
X(),
X(),
Y(True)
]
print('\n'.join([str(i.b) for i in instances]))

#kingkupps
considering as bellow
some_condition = True
class X(object):
def __init__(self,a,c):
self.b = 1
self.a = a
self.c = c
class Y(X):
def __init__(self,a,c):
super(X,self).__init__(a,c)
def __init__(self, some_condition):
super(Y, self).__init__()
if some_condition:
self.b += 1 # or set it to whatever else you want
else:
self.b = -1
File "C:\Users\Alexandre\Documents\PYTHON\Paper_ICESP\teste.py", line 248, in ABM
cells.myfun(a,c)
File "C:\Users\myname\firstfolder\secondfolder\thirdfolder\myscript.py", line 132, in myfun
c = Y(a,c)
File "C:\Users\myname\firstfolder\secondfolder\thirdfolder\myscript.py", line 154, in init
super(X,self).init(a,c)
TypeError: object.init() takes exactly one argument (the instance to initialize)
I suspect that creating a superclass Y inside daughter class Y is interfering in Y. What do you think?

Related

Accesing superclass attribute during subclass construction in Python

Is it possible to access superclass's attributes during class construction?
Here's my code:
class A:
x = 1
class B(A):
x += 1 # <- error
The increment line x += ... is not valid, because x is not defined at this moment. You may suggest doing it in __init__, but I need to initialize the values before the constructor and want to minimize the code.
The code x = A.x + 1 will not work in my case because the A is generated in run-time. So the real code for B looks like
class A:
x: int
def class_gen(params):
class SubA(A):
x = 1
return SubA
class B(class_gen(some_params)):
x += 1
I've found a weird workaround:
x = A.__subclasses__()[-1].x + 1 (indeed the last subclass of A will be the generated super), but it looks too dirty and unstable.
Another workaround is declaring the a 'stub' class variable:
...
_Stub = class_gen(some_params)
class B(_Stub):
x = _Stub.x + 1
but is it also looks urgly. Is there a better way for a perfectionist?
I think you can accomplish it by using __new__ in the subclass.
class A:
x = 1
class B(A):
def __new__(cls, *args, **kwargs):
cls.x += 1
return super().__new__(cls, *args, **kwargs)
b = B()
print(b.x) # 2
There's no easy way to do this. Probably the best is to give your B class a metaclass that handles incrementing of the x attribute for you:
class XIncrementerMeta(type):
def __new__(mcls, name, bases, namespace):
namespace['x'] = bases[0].x + 1
return super().__new__(mcls, name, bases, namespace)
class B(class_gen("some_params"), metaclass=XIncrementerMeta):
pass
print(B.x) # prints 2
If you need each B-like class to have its own kind of manipulation of the x value, you could put it in a classmethod and have an inherited metaclass call it. Or you could even have an __init_subclass__ method in A that calls methods to set the value on its subclasses:
class A:
def __init_subclass__(cls):
cls.set_X()
class SubA(A):
#classmethod
def set_X(cls):
cls.x = 1
class B(SubA):
#classmethod
def set_X(cls):
super().set_X() # get SubA to set an initial value
cls.x += 1 # then update it
print(B.x) # prints 2

Inherit from a "sibling" class?

Imagine I have:
class ABC():
def main(self, x):
self.x = x
class A(ABC):
def afunction(self):
self.a = 2
class B(ABC):
def bfunction(self):
self.b = self.a * self.x
return self.b
How is it possible that class B inherits the self.a and self.x from class A and ABC? (I do not care about inheriting the methods)
If I understand correctly, what you want is to get B to inherit from A.
Notice that what will happen is that it will inherit A variables, and because A inherits from ABC, B will inherit ABC's variables as well.
Also, please note that you will have to initialize the x variable for example inside an B object in order to use the bFunction, and in general it is proper coding to set a constructor as follows:
class ABC():
def __init__(self, x=0):
self.x = x
def main(self, x):
self.x = x
class A(ABC):
def __init__(self, a=2):
super().__init__()
self.a = a
def afunction(self):
self.a = 2
class B(A):
def __init__(self, b=0):
super().__init__()
self.b = b
def bfunction(self):
self.b = self.a * self.x
return self.b
b = B()
b.main(3)
b.afunction()
print(b.bfunction())
Output:
6
If B inherits from A, which inherits from ABC, then B will have ABC and A's methods but neither the 'x' or 'a' attributes which are only set after the methods are run. This works if you rewrite B as:
class B(A):
def bfunction(self, x):
self.main(x)
self.afunction()
self.b = self.a * self.x
return self.b
b = B()
print(b.bfunction(10))
You have to supply 'x' to b.bfunction so that self.b = self.a * self.x works.

Basic confusion with classes & modules (Specially with "self")

I thought that this code would work
class A:
def __init__(self):
self.x = 1
B = self.create_b()
print(B.y)
def create_b(self):
class B:
def __init__(self):
self.y = self.x
return B
A = A()
but I receive the following error
AttributeError: type object 'B' has no attribute 'y'
What am I doing wrong?
You're confusing classes with class instances (not Python modules). In Python class statements are executable and create a callable object that you must then be called to create instance objects of the class that was defined.
Regular methods of a class automatically receive a first argument that's the instance they belong to, and by convention, this argument is usually called self.
Here's what I mean:
class A:
def __init__(self):
self.x = 1
B = self.create_b() # Create B class.
b = B(self) # Create instance of B class passing this instance of A.
print(b.y)
def create_b(self):
class B:
def __init__(self, a_inst):
self.y = a_inst.x
return B
a = A() # -> 1
There are three problems with this code. The first is that since create-b returns a class object, not an instance of the class, B's __init__ was never run. You could solve this with
class A:
def __init__(self):
self.x = 1
B = self.create_b()
b = B()
print(b.y)
def create_b(self):
class B:
def __init__(self):
self.y = self.x
return B
A = A()
The second is that nested classes do not have access to the wrapping method's local namespace like a nested function (closure) would. When attempting self.y = self.x, instances of class B have no special relationship with the instance of A that created them. You could solve this with
class A:
def __init__(self):
self.x = 1
B = self.create_b(self)
b = B()
print(b.y)
def create_b(self):
class B:
def __init__(self, a):
self.y = a.x
return B
A = A()
The third is that python creates a weakref to classes when they are defined that never goes away. Each time you call create_b, you create a small memory leak. You could solve this with
class A:
def __init__(self):
self.x = 1
b = B(self)
print(b.y)
class B:
def __init__(self, a):
self.y = a.x
A = A()

How to make local variable of a method of Superclass available to a subclass where the superclass is called by another class

As you can see the code, I have a super class bar_for_foo_mixin() and I have a subclass myfoo(bar_for_foo_mixin): I am computing a operation self.Z = X+Y in bar() method of superclass.
Now I want the self.z = 0 updated to the computation done in bar() method and inheirt this value to the subclass myfoo(bar_for_foo_mixin): and use it inside subclass.
class bar_for_foo_mixin():
def __init__(self):
self.z = 0
def bar(self, q):
x = 2
y = 8
self.z = x + y + q
class oldfoo():
def __init__(self):
pass
var = bar_for_foo_mixin()
var.bar(10)
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.hello()
Result of the code:
hello 0
Expected result:
hello 20
The bar_for_foo_mixin instance stored in your oldfoo.var class variable is a completely separate instance from the myfoo object you instantiated in the main program, so their instance variable z would not be shared.
If you would like a variable to be shared across all instances of a class, you should make it a class variable instead, and make methods that are dedicated to updating class variables, such as bar_for_foo_mixin.bar, a class method instead:
class bar_for_foo_mixin():
z = 0
#classmethod
def bar(cls, q):
x = 2
y = 8
cls.z = x + y + q
class oldfoo():
def __init__(self):
pass
var = bar_for_foo_mixin()
var.bar(10)
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.hello()
This outputs:
hello 20
You're not even calling the bar method by the new final variable:
class bar_for_foo_mixin():
def __init__(self):
self.z = 0
def bar(self, q):
x = 2
y = 8
self.z = x + y + q
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.bar(10) # <== call it to take effect
final.hello() # ==> hello 20

Python: Getting python class has no attribute

Getting below Attribute error while running below code. Class member function is accessed using self still it is giving error.
class A:
def __init__(self):
self.a=1
def f1(self):
self.b=2
def f2(self):
self.c=3
print(self.a,self.b,self.c)
self.f2()
model = A()
model.f1()
Error:
AttributeError: 'A' object has no attribute 'f2'
A does not have an attribute f2, but it does have an attribute f1 that calls a function f2. f2 is not an instance attribute.
In this case c is no longer an instance attribute, or data attribute, it is now just a local variable. This may or may not be what you were
going for.
class D:
def __init__(self):
self.a = 1
def f1(self):
# Instance attribute declared outside of __init__
self.b = 2
def f2():
c = 3
print(self.a, self.b, c)
f2()
Depending on your development environment you may or may not get a warning about instance attributes being declare outside of the __init__ function. It isn't necessary that you declare them this way, however, it improves readability.
class B:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def f1(self):
def f2():
print(self.a, self.b, self.c)
f2()
This next block is slightly more explicit in what it says about the intent of the code.
class A:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def f1(self):
def f2():
return '{} {} {}'.format(self.a, self.b, self.c)
return f2()
Perhaps you want f2() to be called using method attributes of the
self argument in which case:
class A2:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def f2(self):
print(self.a, self.b, self.c)
def f1(self):
"""Do something that requires calling the self.f2()
print function.
"""
self.f2()
You do not need self when calling the nested function and nor does it need to be contained in the function signature:
class A:
def __init__(self):
self.a=1
def f1(self):
self.b=2
def f2():
c=3
print(self.a,self.b, c)
f2()
model = A()
model.f1()
Output:
1, 2, 3
Its not clear to me that you actually need to define a function within a method just to call it.
So, your code could just as easily be this:
class A:
def __init__(self):
self.a = 1
def f1(self):
self.b = 2
self.f2()
def f2(self):
self.c = 3
print(self.a, self.b, self.c)
model = A()
model.f1()
Output:
1 2 3

Categories