Python Forum
User Subclasses - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: User Subclasses (/thread-32918.html)



User Subclasses - holyghost - Mar-16-2021

Hi,

My current project implementation provides a base class and a child class which provides variables for the base class to use in its methods. For example:

class BaseClass(object):
    
    def print_name(self):
        print(self.name)

class Person1(BaseClass):

    name = "Bob"

bob_inst = Person1()
bob_inst.print_name() 
My project generates custom child classes with unique names that are based on a dataset. The child classes are always inheriting the same base class. The child classes kinda act as containers for unique data, and the base class basically provides different ways to access that child class info.

I'd like to expand my project to provide a subclassable BaseClass to provide a different implementation for specific methods in the BaseClass. For example:

class BaseClass(object):
    
    def print_name(self):
        print(self.name)

class CustomClass(BaseClass):
    
    def print_name(self):
        print("Hello my name is %s" % self.name)

class Person1(CustomClass):

    name = "Bob"

bob_inst = Person1()
bob_inst.print_name() 
The above works fine, but my problem is I'd like the CustomClass in the example to be user-defined. So I won't be able to predict what class name they use. If I can't predict the classname, then my Child class generator cannot provide the correct Base Class to inherit.

My idea is to use the __subclasses__ variable to check if base class has any subclasses, and pass that conditionally to the Child class:

class BaseClass(object):
    
    def print_name(self):
        print(self.name)

class CustomClass(BaseClass):
        
    def print_name(self):
        print("Hello my name is %s" % self.name)                                                                                                                                              

if (len(BaseClass.__subclasses__()) > 0): 
    inherited_name = BaseClass.__subclasses__()[0]
else:
    inherited_name = BaseClass

class Person1(inherited_name):

    name = "Bob"

bob_inst = Person1()
bob_inst.print_name()
Seems a bit hacky to me, so was wondering if there is some better implementation of what I'm trying to do. Another problem I haven't really thought about is that the CustomClass that the user defines will probably live in a different file, so figuring out the importing might be tricky as well...

Thanks!


RE: User Subclasses - buran - Mar-16-2021

I really don't understand why so complicated. It looks like you are really confused about inheritance and instantiation.

At the moment basically you cannot use your BaseClass. You can use only the Person1 class. From what you show you must combine BaseClass and Person1 class into single BaseClass and user can subclass that BaseClass

class BaseClass: # in python3 all classes are "new style" classes and inherit from object
    def __init__(self, name):
        self.name = name
    
    def print_name(self):
        print(self.name)
 
class CustomClass(BaseClass):
    def print_name(self):
        print("Hello my name is %s" % self.name)

foo = CustomClass('Bob')
foo.print_name()

bar = BaseClass('Joe')
bar.print_name()
Note, there is no need to generate new classes for every name from dataset (because it sounds that's what you are doing). That's what the instances are.
BaseClass may reside in different module from the one in which CustomClass is defined, user just need to import BaseClass


RE: User Subclasses - holyghost - Mar-16-2021

Thanks for the feedback, appreciated.

Yea I guess I wasn't descriptive enough on my classes. But you are right, I'm not directly using the base class, I don't think I'll ever need to directly use it. Was just housing common methods that are used in all the sub-classes. Felt like it would be redundant to add them to the sub classes. Maybe this isn't correct thing to do?

Issue is that in my project, I don't want the child class instances to be touched by the end-user. They have predefined instance names that must remain the same. My example in my original post wasn't very accurate to what I'm actually doing, was trying to simplify it too much.

Here is a better representation, still simplified though:
# File: hierarchy.py
# User should not touch this file..

class BASE(object):

    def method(self):
       print("My value is %s" % self.value)

class SubHier(BASE):

    def __init__(self, value):
        self.value = value


class Top(BASE):

    def __init__(self, name):
        self.name = name

    def build(self):
        self.HIER1 = SubHier(1)
        self.HIER2 = SubHier(2)

TOP_INST = Top("top_hier")
TOP_INST.build()
Anyways, I wanted the TOP/SubHier classes to be hidden from the user, and the user can only access the pre-generated instances. I'm treating this as more of a data structure that can be accessed (kinda like a dictionary with methods to access it). So the Top and SubHier classes are more containers for the data and the base class provides different functions to access that data in different ways.

So the user code (in separate file) would just import the hierarchy, and access it through the base class methods:

# File: user.py

from hierarchy import TOP_INST

# Access hierarchy...
TOP_INST.HIER1.method()
TOP_INST.HIER2.method()
I wanted to have some hook to let the user edit or extend the 'access' methods in the BASE class, without needing to change how the hierarchy classes are instantiated. That's why I was considering extending the BASE class.

Thanks!


RE: User Subclasses - deanhystad - Mar-17-2021

An interesting, and scary, feature of Python is that you can redefine the methods of a class during runtime. You can also add "methods" to an instance so two instances of the same class will behave differently when the same method is called.

In this example I have class B which is a subclass of A. I would like instances of class B to do subtraction when math() is called. I dynamically add a math() method to B.
class A:
    def __init__(self, value):
        self.value = value

    def math(self, b):
        return self.value + b

class B(A):
    def print(self, b):
        print(self.math(b))

x = B(5)
x.print(3)

def math(self, b):
    return self.value - b

B.math = math

x.print(3)
Output:
8 2
But your question is about how to insert a class between A and B. In this example I tell class B that it should first look to class C for methods and then class A. Class C has no relationship to either class A or B.
class A:
    def __init__(self, value):
        self.value = value

    def math(self, b):
        return self.value + b

class B(A):
    def print(self, b):
        print(self.math(b))

class C:
    def math(self, b):
        return self.value ** b

x = B(5)
x.print(3)
B.__bases__ = (C,A)
x.print(3)
Output:
8 125



RE: User Subclasses - buran - Mar-17-2021

Sorry, I still don't fully understand your design or why you are doing it like this.
Anyway, maybe something like this is what you want.


hierarchy.py
class Parent:
    def say(self):
        print(f'Hello, {self.name}')

try:
    import myhook
    hook = myhook.Child
except (ModuleNotFoundError, AttributeError): # no myhook.py or no Child class in it
    class Child:
        pass
    hook = Child

class GrandChild(Parent, hook):
    def __init__(self, name):
        self.name = name


foo = GrandChild('John Doe')
Then, if user want to customize they will provide a module with standard name, e.g myhook.py with class with predefined name Child.
e.g.
myhook.py
class Child:
    def hi(self):
        print(f'Hi, {self.name}')
then in user.py

from hierarchy import foo
foo.hi()



RE: User Subclasses - deanhystad - Mar-17-2021

I think holyghost is trying to make something like a C++ interface class. I don't think such a thing is needed in Python. Interfaces are a bandaid to fix the broken C++ inheritance mechanism. A fix that isn't needed by Python due to how it does message/method binding.

I thik it is time for a more realistic example. The simple examples are not explaining why you need this mechanism. Maybe you don't and there is a better way to solve your problem.


RE: User Subclasses - buran - Mar-17-2021

I don't have experience with C++, so maybe that's why I have hard time to understand their goal.