I have one base class and other classes inherit from this class (subclasses). There is one common method in base class that I want to use subclass static properties If subclass has the properties; otherwise default base class property should be used.
I have written following code to do such a thing:
class Base:
prp1 = 1
prp2 = 2
def __init__():
pass
def method1(self):
# print subclass prp1 and prp2 if exist (how to do this?)
class Subclass(Base):
prp1 = 3
prp2 = 4
a = Subclass()
a.method1() # should print subclass properties (3, 4)
How to get around this problem?
Thanks in advance.
Your code works just fine - you can reference prp1 and prp2 using self, so:
def method1(self):
print(self.prp1)
print(self.prp2)
Will reference the properties from the instance of the class you're calling it on.
Furthermore, if you don't define prp2 on the subclass, Python will fallback to prp2 from Base, which I assume is what you want.
Calling the class from instance should do the thing:
print(self.__class__.prp1)
Related
What is a "Pythonic" way to define a class that does not need any constructor parameters?
class MyClass:
# class body
or do we need an explicit constructor? i.e.
class MyClass:
def __init__:
pass
# class body
Your first approach is good enough, unless you want to only use class attributes and not instance attributes
Also every class in Python inherits from object, as explained in detail here
class MyClass:
pass
An example of such classes might be as follows
A class to store multiple class attributes
class MyClass:
a = 1
b = 2
print(MyClass.a)
#1
print(MyClass.b)
#2
A custom exception where the constructor is implicitly taken from the base class
class MyException(Exception):
pass
raise MyException
# raise MyException
#__main__.MyException
How does communication between base classes and inherited classes work?
I have a data class in my python code ( storing all important values, duh ), I tried inheriting new subclasses from the data base class, everything worked fine except the fact that the classes were not actually communicating ( when one class variable was changed in a subclass, the class attribute was not changed in the base class nor any other subclasses.
I guess I just failed to understand how inheritance works, my question is: Does inheritance keep any connection to the base classes, or are the values set at the time of inheritance?
If there is any connection, how do you easily manipulate base class variables from a subclass ( I tried it with the cls variable to access base class variables, didn't work out )
Example
class Base:
x = 'baseclass var' # The value I want to edit
class Subclass(Base):
#classmethod(cls)
???edit_base_x_var_here??? # This is the part I don't know
Well, you could do that in this way:
class Base:
x = 'baseclass var' # The value I want to edit
class Subclass(Base):
#classmethod
def change_base_x(cls):
Base.x = 'nothing'
print Subclass.x
Subclass.change_base_x()
print Subclass.x
furthermore, you don't have to use #classmethod, it could be staticmethod, because you don't need current class object cls:
class Base:
x = 'baseclass var' # The value I want to edit
class Subclass(Base):
#staticmethod
def change_base_x():
Base.x = 'nothing'
EDITED:
According to your question, about other way. Yes it is, but not so pretty. I would say more. If you want to change variable of base class, then you will do it globally though, so that option with assigning to Base.x is the best way you can achieve that.
I have a class hierarchy in a module that I want to extend.
The module to be extended looks something like this.
Module foo:
class bar(object): pass
class spam(bar): pass
class eggs(bar): pass
Now I want to extend these classes:
class my_bar(foo.bar):
def new_func(): pass
class my_spam(foo.spam): pass
class my_eggs(foo.eggs): pass
Doing so, a new function new_func() in my_bar would not be available in a my_spam instance using
my_spam_instance.new_func()
What is the best ("most pythonic") way to achieve this? I thought of multiple inheritance, like this:
class my_bar(foo.bar): pass
class my_spam(foo.bar, my_bar): pass
class my_eggs(foo.eggs, my_bar): pass
Though I never really used it before and I am not sure this is the best way.
You don't even need to inherit my_bar from bar
pythonic will be adding Mixin, which is actually a base class, but not inherited
class NewFuncMixin():
def new_func(): pass
And add it to new classes
class my_bar(foo.bar, NewFuncMixin): pass
class my_spam(foo.spam, NewFuncMixin): pass
class my_eggs(foo.eggs, NewFuncMixin): pass
What about a mixin class? The pattern is
class My_mixin( object):
def new_func(self): pass
class My_spam( My_mixin, foo.spam): pass
class My_eggs( My_mixin, foo.eggs): pass
mixins should inherit from object, and go on the left of the inheritance list so that the mixin class methods get name priority. Within the mixin you can then wrap any method of the superclass:
class My_mixin( object):
def bar_method( self):
# stuff
bar_result = super( My_mixin, self).bar_method()
# more stuff
return bar_result # or my_result based on bar_result
You can of course completely override the method instead of wrapping it.
My base class has a method that returns an instance of itself. When I write my subclass, is there any way to make this instance an instance of my subclass instead of the base class, without modifying the code of the base class or rewriting the whole base class method into my subclass method ?
Example :
class A:
def __init__(self,x):
self.x = x
def add(self):
self.x += 2
def new(self,z):
n = A(z)
return n
class B(A):
def __init__self():
A.__init__(self,x)
Here if I do :
a = B(10)
b = a.new(4)
Then b will be an instance of A and not an instance of B like I want it to be.
In this simple example I could just override the method in the B class but in my program I don't want to, it would just ruin portability because I have no control over the base class since it is part of another package.
Is there any way to do this ?
Make it a class method:
#classmethod
def new(cls, z):
return cls(z)
Ideally, instead of:
def new(self,z):
n = A(z)
return n
You'd have:
def new(self, z):
n = self.__class__(z)
return n
That way, you're using the class of in instance the method was called on, instead of hardcoding the class that you're creating a new instance of.
However, since you've mentioned you can't modify the base class, you have two options:
Override the method in the derived class
Monkey patch the base class
Request whoever maintains the base class to make this change for you
You've said you don't want to override it because it's bad for portability. I would argue that this isn't true - if the base class is likely to be updated such that the behaviour of it's public API changes, it's already bad for portability because who knows what breaking changes it might introduce. If the behaviour is going to stay consistent (even if the implementation changes) it should be safe to override.
The other option is to monkey patch the base class. This would have the same problems as overriding in the base class, the difference is that other subclasses would get the behaviour too - not just those that inherit from B.
You'd monkey patch like this (outside of a class definition):
def new_new(self, z):
n = self.__class__(z)
return n
A.new = new_new
Use __class__:
n = self.__class__(z)
return n
...
#jonrsharpe's answer is better
I was trying to override a member of a Python (2.7) class with a property, as shown in the following code:
class Base:
def __init__(self):
self.foo = 1
class Derived(Base):
foo = property(lambda self: 2)
print Derived().foo
However, the last line prints 1 instead of 2. From the way I thought properties are supposed to work (ie., easily change a member to a function later on), this seems counter-intuitive to me. Am I missing something? Is there some workaround?
This doesn't work because you aren't using a new-style class. Properties are descriptors which only work on new-style classes. What your code is doing is this:
You create a class Derived with a class attribute foo. Then when you create an instance of the class, Base.__init__ takes over since Derived has no __init__ and you add the instance attribute foo which takes precedence to the class attribute.
If you change:
class Base: #old style class
to:
class Base(object): #new style class
You'll run into an entirely new problem, mainly that your property doesn't have an appropriately defined setter, so when you do self.foo = 1 in Base.__init__ you'll get an AttributeError