Skip to content

Inheriting and extending Python classes in C# #862

Open

Description

@lostmsu

Environment

  • Pythonnet version: 2.4.0
  • Python version: 3.6
  • Operating System: Win10 x64

Details

I am trying to let a user of my library inherit a Python class, and override some of its behavior. Simply declaring a class with the same set of methods, and calling ToPython on it somewhat works thanks to Python's duck typing.

Problem is that approach fails to pass isinstance and obj is Class tests in the 3rd-party Python code.

If there's no existing way to deal with it, I'd be happy to implement the necessary machinery, if somebody would give some directions on where to start.

Activity

  1. filmor commented on May 15, 2019

    @filmor
    Member

    I'm not sure what you mean by obj is Class here, but isinstance can indeed be overridden, and we do so already: https://github.com/pythonnet/pythonnet/blob/master/src/runtime/metatype.cs#L259

    In metatype, we register __instancecheck__ (the one I linked) and __subclasscheck__ for this purpose, you can try to extend them for your use case.

  2. lostmsu commented on May 15, 2019

    @lostmsu
    MemberAuthor

    @filmor is it possible to use MetaType to represent my C# class as being derived from a specific Python type? Or do I have to simply go with __instancecheck__?

    Can MetaType be used for A (C#) derives from B (C#) deriving from C (Python)?

    obj is Class is an "old" way of doing isinstance(obj, Class). I am not sure if they have the same semantics.

  3. filmor commented on May 15, 2019

    @filmor
    Member

    obj is Class is not the old way of doing isinstance, it's an entirely different thing (checking that obj and Class are the exact same objects).

    The issue here is that B does not derive from the Python class. In __instancecheck__ we solve this by checking whether the object we are looking at is of our metaclass (https://github.com/pythonnet/pythonnet/blob/master/src/runtime/metatype.cs#L287) and if that's the case, checking if it's "assignable from" (https://github.com/pythonnet/pythonnet/blob/master/src/runtime/metatype.cs#L300).

    What you could do is introducing an attribute that is checked in DoInstanceCheck:

     [Python.DerivesFromPython("package.class.bla")]
     class MyClass { ... }
    

    Alternatively, you could try to override __instancecheck__ directly on your (base) class.

  4. lostmsu commented on May 15, 2019

    @lostmsu
    MemberAuthor

    @filmor thanks for your help. I will try that approach tomorrow.

    Also, excuse my lack of knowledge about Python. Using Python.NET is actually the way I am trying to avoid it as much as possible :)

  5. lostmsu commented on May 16, 2019

    @lostmsu
    MemberAuthor

    @filmor looked at some docs about isinstance and its relationship to __instancecheck__, and can't figure how to apply it to my problem.

    Suppose I have this 3rd party code (so I can't modify it):

    class Base:
      pass
    
    def accept(base_obj):
      if not isinstance(base_obj, Base):
        raise TypeError()
      print("OK!")

    And I want to define a derived class in C# like this:

    class Derived {
      ...
    }
    
    accept(new Derived().ToPython());

    Problem is, according to my understanding from SO, I have to override __instancecheck__ in Base.__class__ for it to recognize my instance of Derived to be an instance of Base. But I can't! I can only change what is in Derived.

    Is there a different way to tell Python, that Derived is actually "derived" from Base?

  6. lostmsu commented on May 16, 2019

    @lostmsu
    MemberAuthor

    @filmor I looked at the Python source code, and this check eventually goes down to walking MRO in PyType_IsSubtype: https://hg.python.org/cpython/file/v3.5.3/Objects/typeobject.c#l1345

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions