0

I was thinking about writing a class decorator which would check whether a particular method inherited from object had been overridden or not.

import io

def check_str_method(kls:type) -> type:
    with io.StringIO() as strm:
        if "__str__" in kls.__dict__:
            print("`__str__` is in `__dict__`", file = strm)
        if "__str__" in dir(kls):
            print("`__str__` is in container returned by `dir(kls)`", file = strm)
        str_method = getattr(kls, "__str__")
        if str_method == object.__str__:
            pass
        if str_method == object.__str__:
            pass
        return kls

@check_str_method
class ChildClass1:
    pass

@check_str_method
class ChildClass2:
    def __str__(self):
        return "I HAVE OVERRIDDEN __str__"

obj1 = ChildClass1()
obj2 = ChildClass2()

print("obj1...", str(obj1))
print("obj2...", str(obj2))

What is the proper pythonic way to do this? Do we check mro() (the method resolution order?)

Do we search in __bases__?

Toothpick Anemone
  • 4,290
  • 2
  • 20
  • 42
  • 2
    `kls.__str__ is object.__str__` should do it. And `if "__str__" in dir(kls)` can be expanded to only compare against methods and skip `__class__` and `__doc__`. Not sure what the exact use-case is but a decorator like `check_str_method` can be made more generic by accepting an argument: `@check_object_method("__str__")` etc. – Ashwini Chaudhary Mar 21 '23 at 03:26
  • 1
    I'm a bit confused what you're asking here. You have some questions, but your code already seems to do the check you want (though it ignores the results, with `pass` and a `StringIO` that gets some values that go on to be discarded). – Blckknght Mar 23 '23 at 21:27

1 Answers1

0

My answer is based on a comment by Ashwini Chaudhary.

Some code such as the following might work, but I am hoping that someone will post a better answer and that their answer will get more up-votes than mine.

class tools:

    @classmethod 
    def override_str_method(this_class, kls:type) -> type:
        # if someone did not override the `__str__` method... 
        if "__str__" is object.__str__:
            # ... and if the class is iterable...
            if hasattr(kls, "__iter__"):
                # ... then override the string method ...
                # ... definir un método de sarta
                def __str__(self, key:int):
                    """
                        `__str__` provides an information-lossy
                        method which displays a human-readable
                        abridged version of the object for 
                        debugging purposes.  

                        If you want enough information to 
                        re-construct the object, then use
                        `__repr__`
                    """
                    lyst = list()
                    it = iter(self)
                    try:
                        lefty = next(it)
                        lyst.append(lyst) 
                        while True:
                            righty = next(it)
                            lyst.append("...")
                            lyst.append(righty)
                    except StopIteration:
                        stryng = str()
                    return str(lyst) 
                # termination of definition of __str__
                # terminar de definición de __sarta__ 
            # end check to see if class is iterable 
       # end check for if `__str__` is the default value 
    # end method definition

    @classmethod 
    def override_repr_method(this_class, kls:type) -> type:
        # if someone did not override the `__repr__` method... 
        if "__repr__" is object.__repr__:
            # ... and if the class is iterable...
            if hasattr(kls, "__iter__"):
                # ... then override the representation method ...
                # ... definir un método de representación 
                def __repr__(self, key:int):
                    """
                        `__repr__` provides a string containing
                        sufficient information to re-construct the object.   
                    """
                    lyst = list(iter(self))
                    return repr(lyst) 
                # termination of definition of __repr__
                # terminar de definición de __representación__ 
            # end check to see if class is iterable 
       # end check for if `__repr__` is the default value 
    # end method definition 
Toothpick Anemone
  • 4,290
  • 2
  • 20
  • 42
  • 1
    This code seems to be doing something completely different than what your question is asking about. It's *creating* an override method, rather than checking if one already exists. What is your real question here? This feels like an [XY problem](https://meta.stackexchange.com/q/66377/223254). – Blckknght Mar 23 '23 at 21:31