pythonpandasdataframeisinstance

Faking whether an object is an Instance of a Class in Python


Suppose I have a class FakePerson which imitates all the attributes and functionality of a base class RealPerson without extending it. In Python 3, is it possible to fake isinstance() in order to recognise FakePerson as a RealPerson object by only modifying the FakePerson class. For example:

class RealPerson():
    def __init__(self, age):
        self.age = age

    def are_you_real(self):
        return 'Yes, I can confirm I am a real person'

    def do_something(self):
        return 'I did something'

    # Complicated functionality here

class FakePerson(): # Purposely don't extend RealPerson
    def __init__(self, hostage):
        self.hostage = hostage

    def __getattr__(self, name):
        return getattr(self.hostage, name)

    def do_something(self):
        return 'Ill pretend I did something'

    # I don't need complicated functionality since I am only pretending to be a real person.


a = FakePerson(RealPerson(30))
print(isinstance(a, RealPerson))

The context of this is suppose I have a class that imitates most / all of the functionality of a Pandas DataFrame row (a namedtuple object). If I have a list of rows list_of_rows, Pandas generates a DataFrame object by pandas.DataFrame(list_of_rows). However, since each element in list_of_rows is not a namedtuple and just a 'fake', the constructor can't recognise these 'fake' row objects as real rows even if the fake object does fake all the underlying methods and attributes of the Pandas namedtuple.


Solution

  • You may need to subclass your RealPerson class.

    class RealPerson:
        def __init__(self, age):
            self.age = age
    
        def are_you_real(self):
            return 'Yes, I can confirm I am a real person'
    
        def do_something(self):
            return 'I did something'
    
        # Complicated functionality here
    
    class FakePerson: # Purposely don't extend RealPerson
        def __init__(self, hostage):
            self.hostage = hostage
    
        def __getattr__(self, name):
            return getattr(self.hostage, name)
    
        def do_something(self):
            return 'Ill pretend I did something'
    
        # I don't need complicated functionality since I am only pretending to be a real person.
    
    
    class BetterFakePerson(RealPerson):
        pass
    
    BetterFakePerson.__init__ = FakePerson.__init__
    BetterFakePerson.__getattr__ = FakePerson.__getattr__
    BetterFakePerson.do_something = FakePerson.do_something
    
    a = FakePerson(RealPerson(30))
    print(isinstance(a, RealPerson))
    
    b = BetterFakePerson(RealPerson(30))
    print(isinstance(b, RealPerson))
    

    Hope this answer would not be too late for you LOL