Easily editing base class variables from inherited class - python

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.

Related

Using subclass static property in base class

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)

Get name of class another class is instantiated inside of in Python

Is it possible to get the name of a python class in another class that was instantiated inside the first class.
Let me give you an example.
class SubClass:
top_level_name = None # name class it is instantiated in e.g. TopLevelClass
class TopLevelClass:
subclass = SubClass()
I understand that I can write the following...
class SubClass:
def __init__(self, class_name):
self.top_level_name = class_name
class TopLevelClass:
subclass = SubClass(class_name)
def __init__(self):
self.class_name = self.__class__.__name__
However, it would be nice to do it without needing to pass the class name as an argument when the class is initialized.
Is this possible, just wishful thinking, or a really bad idea for some reason I have not thought of yet.
I would suggest revisiting the design for these two classes. Having the instantiated class be aware of the calling class violates design principals of encapsulation and abstraction. It also creates a cyclic dependency (in this case only a logical dependency as only the name of the class is known). If you're using the class name as some kind of identifier for the instantiated class, you can pass in an id string in the constructor as you have in your example.

Python: Overriding a member with a property?

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

Access class object builtin values from class (not class member) scope

How can you access class values from within the top level class scope? What I mean by that is, how do you do something like:
class FooClass(object):
zeroith_base = __bases__[0]
.
.
.
What I'm specifically trying to do in this case is derive the metaclasses of all base classes to dynamically generate a metaclass that subclasses all the base classes' metaclasses to get past metclass conflict problems. I found http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/, and while all the concepts make sense to me, the actual code of the recipe is just beyond my ability to follow it. I don't want to use code I can't understand though, so instead, I tried to implement my own, more rudimentary system, but I'm stuck at square one trying to inspect the class object during creation.
You cannot inspect a class prior to its creation, and it has not yet been created yet until the suite of statements, or class body, have finished executing. The first time you have access to this information would be in the MetaClass.__new__ method of the class creating the class in question, or the execution of the thing creating the class in question, which technically need not be a meta-class or a class at all (as in the example below).
Here is a very rough prototype that probably does not work in all cases, but works in the simple case, and is probably easier to follow than the recipe.
def meta_class_synthesize(name, bases, attrmap):
seen = set()
seen_add = seen.add
metas = [type(base) for base in bases]
metas = tuple([
meta for meta in metas
if meta is not type and meta not in seen and not seen_add(meta)])
if not metas:
return type(name, bases, attrmap)
elif len(metas) == 1:
return metas[0](name, bases, attrmap)
newmeta_name = "__".join(meta.__name__ for meta in metas)
newmeta = type(newmeta_name, metas, {})
return newmeta(name, bases, attrmap)
class M_A(type):
pass
class M_B(type):
pass
class A:
__metaclass__ = M_A
class B:
__metaclass__ = M_B
class C(A, B):
__metaclass__ = meta_class_synthesize
print type(C) # prints "<class '__main__.M_A__M_B'>"
You'll find that __bases__ is not part of the class namespace. The class namespace is passed to the metaclass as the third parameter; the bases are passed as the second parameter. They are totally separate until the class is created.
So what you'll need to do is write a metaclass that synthesizes the metaclass you want, then uses that to create the class. I have no idea if that'll actually work, but I can't see any reason why it wouldn't.

How to change baseclass

I have a class which is derived from a base class, and have many many lines of code
e.g.
class AutoComplete(TextCtrl):
.....
What I want to do is change the baseclass so that it works like
class AutoComplete(PriceCtrl):
.....
I have use for both type of AutoCompletes and may be would like to add more base classes, so how can I do it dynamically?
Composition would have been a solution, but I do not want to modify code a lot.
any simple solutions?
You could have a factory for your classes:
def completefactory(baseclass):
class AutoComplete(baseclass):
pass
return AutoComplete
And then use:
TextAutoComplete = completefactory(TextCtrl)
PriceAutoComplete = completefactory(PriceCtrl)
On the other hand depending on what you want to achieve and how your classes look, maybe AutoComplete is meant to be a mixin, so that you would define TextAutoComplete with:
class TextAutocomplete(TextCtrl, AutoComplete):
pass
You could use multiple inheritance for this:
class AutoCompleteBase(object):
# code for your class
# remember to call base implementation with super:
# super(AutoCompleteBase, self).some_method()
class TextAutoComplete(AutoCompleteBase, TextCtrl):
pass
class PriceAutoComplete(AutoCompleteBase, PriceCtrl):
pass
Also, there's the option of a metaclass:
class BasesToSeparateClassesMeta(type):
"""Metaclass to create a separate childclass for each base.
NB: doesn't create a class but a list of classes."""
def __new__(self, name, bases, dct):
classes = []
for base in bases:
cls = type.__new__(self, name, (base,), dct)
# Need to init explicitly because not returning a class
type.__init__(cls, name, (base,), dct)
classes.append(cls)
return classes
class autocompletes(TextCtrl, PriceCtrl):
__metaclass__ = BasesToSeparateClassesMeta
# Rest of the code
TextAutoComplete, PriceAutoComplete = autocompletes
But I'd still suggest the class factory approach already suggested, one level of indentation really isn't that big of a deal.
You could modify the __bases__ tuple. For example you could add another baseclass:
AutoComplete.__bases__ += (PriceCtrl,)
But in general I would try to avoid such hacks, it quickly creates a terrible mess.

Categories

Resources