[Python.NET] Inheriting from abstract .NET class

Denis Akhiyarov denis.akhiyarov at gmail.com
Fri Aug 18 00:05:24 EDT 2017


Hi Henning,

Your question about abstract classes in pythonnet reposted at stackoverflow
received a lot of attention recently:

https://stackoverflow.com/questions/39659469/how-to-inherit-from-an-abstract-base-class-written-in-c-sharp

Thanks,
Denis

On Tue, Sep 27, 2016 at 11:56 AM, Denis Akhiyarov <denis.akhiyarov at gmail.com
> wrote:

> Henning,
>
> It is very questionable if "protected" should be available for overriding
> in Python, since we are not really doing compile time overriding in a .NET
> class with all sorts of differences in class compilation vs runtime
> emission.
>
> But as a quick workaround you can add protected in this method in
> pythonnet:
>
> private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuilder typeBuilder)
>
> Let us know about the result.
>
> Cheers,
> Denis
>
> On Tue, Sep 27, 2016 at 2:49 AM, Henning Moeller <HMoeller at comprion.com>
> wrote:
>
>> Hi Denis,
>>
>>
>>
>> thank you again. That helped a lot.
>>
>>
>>
>> But – I’m sorry to bother you again. In the classes I really have to use,
>> some of the virtual methods are protected. Those are not resolved by
>> pythonnet. Only public virtual is recognized and overridden by the
>> inherited class. See the (only slightly) altered example:
>>
>>
>>
>> namespace PythonBaseClass
>>
>> {
>>
>>     using System;
>>
>>
>>
>>     public class Door
>>
>>     {
>>
>>         public virtual void Open()
>>
>>         {
>>
>>             if (!IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public virtual void Close()
>>
>>         {
>>
>>             if (IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public virtual bool IsOpen()
>>
>>         {
>>
>>             Console.WriteLine("Door.IsOpen()");
>>
>>             return false;
>>
>>         }
>>
>>
>>
>>         *protected* virtual void Toggle()
>>
>>         {
>>
>>             Console.WriteLine("Door.Toggle()");
>>
>>         }
>>
>>     }
>>
>> }
>>
>>
>>
>> The Python code has just been altered so that the namespace is properly
>> set. Running the example comes with the following output:
>>
>>
>>
>> Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500
>> 32 bit (Intel)] on win32
>>
>> Type "help", "copyright", "credits" or "license" for more information.
>>
>> >>> from PythonInheritedClass import *
>>
>> >>> d = StringDoor()
>>
>> >>> d.status
>>
>> 'closed'
>>
>> >>> d.Open()
>>
>> StringDoor.IsOpen()
>>
>> *Door.Toggle()*
>>
>> >>>
>>
>>
>>
>> Any ideas? This looks a little bit more “doable” than the abstract thing.
>>
>>
>>
>> BR,
>>
>>
>>
>> Henning
>>
>>
>>
>> *From:* PythonDotNet [mailto:pythondotnet-bounces+hmoeller=
>> comprion.com at python.org] *On Behalf Of *Denis Akhiyarov
>> *Sent:* Montag, 26. September 2016 20:16
>> *To:* A list for users and developers of Python for .NET <
>> pythondotnet at python.org>
>> *Subject:* Re: [Python.NET] Inheriting from abstract .NET class
>>
>>
>>
>> Hi Henning,
>>
>>
>>
>> This feature was implemented by @tonyroberts in 2013 and is tested in CI
>> with test_subclass.py file.
>>
>>
>>
>> According to these tests, the missing piece in your code is defining
>> explicitly __namespace__ on the .NET class derived in Python:
>>
>>
>>
>> In [11]: class StringDoor1(Door):
>>
>>    ....:     __namespace__ = "PythonBaseClass"
>>
>>    ....:     def __init__(self):
>>
>>    ....:         self.status = "closed"
>>
>>    ....:
>>
>>    ....:     def IsOpen(self):
>>
>>    ....:         print "StringDoor.IsOpen()"
>>
>>    ....:         return self.status == "open"
>>
>>    ....:
>>
>>    ....:     def Toggle(self):
>>
>>    ....:         print "StringDoor.Toggle()"
>>
>>    ....:         if self.status == "open":
>>
>>    ....:             self.status = "closed"
>>
>>    ....:         else:
>>
>>    ....:             self.status = "open"
>>
>>
>>
>> In [12]: d = StringDoor1()
>>
>>
>>
>> In [13]: d.status
>>
>> Out[13]: 'closed'
>>
>>
>>
>> In [14]: d.Open()
>>
>> StringDoor.IsOpen()
>>
>> StringDoor.Toggle()
>>
>>
>>
>> In [15]: d.status
>>
>> Out[15]: 'open'
>>
>>
>>
>>
>>
>>
>>
>> Thanks,
>>
>> Denis
>>
>>
>>
>> On Mon, Sep 26, 2016 at 9:19 AM, Henning Moeller <HMoeller at comprion.com>
>> wrote:
>>
>> Hi Denis,
>>
>>
>>
>> Thanks for your fast response. Sounds completely reasonable to me. And
>> this has not been too much of an issue for me.
>>
>>
>>
>> I got rid of the abstract base class simply by providing an “empty”
>> implementation and using a non-abstract base class. No need for meta
>> classes any more. This way, I got rid of error messages. Great!
>>
>>
>>
>> Unfortunately, there seem to be an issue when calling a virtual method
>> inside the C# implementation. Even when overriding this virtual method in
>> Python, it’s still the base class’ implementation which is called.
>>
>>
>>
>> See the new simple base class defined in C#:
>>
>>
>>
>> namespace PythonBaseClass
>>
>> {
>>
>>     using System;
>>
>>
>>
>>     public class Door
>>
>>     {
>>
>>         public virtual void Open()
>>
>>         {
>>
>>             if (!IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public virtual void Close()
>>
>>         {
>>
>>             if (IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public virtual bool IsOpen()
>>
>>         {
>>
>>             Console.WriteLine("Door.IsOpen()");
>>
>>             return false;
>>
>>         }
>>
>>
>>
>>         public virtual void Toggle()
>>
>>         {
>>
>>             Console.WriteLine("Door.Toggle()");
>>
>>         }
>>
>>     }
>>
>> }
>>
>>
>>
>> The consuming Python code now looks like this:
>>
>>
>>
>> import clr
>>
>> from PythonBaseClass import Door
>>
>>
>>
>> class StringDoor(Door):
>>
>>     def __init__(self):
>>
>>         self.status = "closed"
>>
>>
>>
>>     def IsOpen(self):
>>
>>         print "StringDoor.IsOpen()"
>>
>>         return self.status == "open"
>>
>>
>>
>>     def Toggle(self):
>>
>>         print "StringDoor.Toggle()"
>>
>>         if self.status == "open":
>>
>>             self.status = "closed"
>>
>>         else:
>>
>>             self.status = "open"
>>
>>
>>
>> But the output does not look like expected:
>>
>>
>>
>> Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500
>> 32 bit (Intel)] on win32
>>
>> Type "help", "copyright", "credits" or "license" for more information.
>>
>> >>> from PythonInheritedClass import StringDoor
>>
>> >>> d = StringDoor()
>>
>> >>> d.status
>>
>> 'closed'
>>
>> >>> d.Open()
>>
>> *Door.IsOpen()*
>>
>> *Door.Toggle()*
>>
>> >>> d.status
>>
>> *'closed'*
>>
>> >>>
>>
>>
>>
>> From my understanding, the output should rather read “
>> StringDoor.<something>()” instead of “Door.<something>()”. Obviously,
>> only the base implementation is called but the overridden methods are
>> ignored.
>>
>>
>>
>> Also a limitation of inheriting C# classes in pythonnet?
>>
>>
>>
>> BR,
>>
>>
>>
>> Henning
>>
>>
>>
>> *From:* PythonDotNet [mailto:pythondotnet-bounces+hmoeller=
>> comprion.com at python.org] *On Behalf Of *Denis Akhiyarov
>> *Sent:* Donnerstag, 22. September 2016 19:38
>> *To:* A list for users and developers of Python for .NET <
>> pythondotnet at python.org>
>> *Subject:* Re: [Python.NET] Inheriting from abstract .NET class
>>
>>
>>
>> You are not a "Python n00b" based on metaclass usage!
>>
>>
>>
>> My recommendation is to keep simple integration layer between CPython and
>> .NET, hence metaclasses were/are not supported.
>>
>>
>>
>> But contributions are welcome! Although I expect this to be a tremendous
>> undertaking based on reviewing multiple sources.
>>
>>
>>
>> Note that metaclass is a very different low-level concept from
>> higher-level abstract classes in .NET, hence direct mapping (e.g.
>> `.register()` ) is not feasible.
>>
>>
>>
>> Thanks,
>>
>> Denis
>>
>>
>>
>> On Thu, Sep 22, 2016 at 10:04 AM, Henning Moeller <HMoeller at comprion.com>
>> wrote:
>>
>> Hello out there,
>>
>>
>>
>> I’m trying to inherit from an abstract .NET base class in Python (2.7).
>> I’m a Python n00b but from what I understood…
>>
>>
>>
>> Here’s what I managed to do in Python only and which works fine:
>>
>>
>>
>> [File: room.py] -------
>>
>> import abc
>>
>>
>>
>> class Room(object):
>>
>>     def __init__(self, door):
>>
>>         self.door = door
>>
>>
>>
>>     def open(self):
>>
>>         self.door.open()
>>
>>
>>
>>     def close(self):
>>
>>         self.door.close()
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.door.is_open()
>>
>>
>>
>> class Door(object):
>>
>>     __metaclass__ = abc.ABCMeta
>>
>>
>>
>>     def open(self):
>>
>>         if not self.is_open():
>>
>>             self.toggle()
>>
>>
>>
>>     def close(self):
>>
>>         if self.is_open():
>>
>>             self.toggle()
>>
>>
>>
>>     @abc.abstractmethod
>>
>>     def is_open(self):
>>
>>         pass
>>
>>
>>
>>     @abc.abstractmethod
>>
>>     def toggle(self):
>>
>>         pass
>>
>>
>>
>> class StringDoor(Door):
>>
>>     def __init__(self):
>>
>>         self.status = "closed"
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.status == "open"
>>
>>
>>
>>     def toggle(self):
>>
>>         if self.status == "open":
>>
>>             self.status = "closed"
>>
>>         else:
>>
>>             self.status = "open"
>>
>>
>>
>> class BooleanDoor(Door):
>>
>>     def __init__(self):
>>
>>         self.status = True
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.status
>>
>>
>>
>>     def toggle(self):
>>
>>         self.status = not (self.status)
>>
>>
>>
>> Door.register(StringDoor)
>>
>> Door.register(BooleanDoor)
>>
>> -------
>>
>>
>>
>> Now, all I did was to replace the abstract base class Door by a C#
>> representation:
>>
>>
>>
>> [File: PythonAbstractBaseClass.dll] -------
>>
>> namespace PythonAbstractBaseClass
>>
>> {
>>
>>     public abstract class Door
>>
>>     {
>>
>>         public virtual void Open()
>>
>>         {
>>
>>             if (!IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public virtual void Close()
>>
>>         {
>>
>>             if (IsOpen())
>>
>>                 Toggle();
>>
>>         }
>>
>>
>>
>>         public abstract bool IsOpen();
>>
>>         public abstract void Toggle();
>>
>>     }
>>
>> }
>>
>> -------
>>
>>
>>
>> Removing Door from the Python part and importing it from the .NET
>> assembly instead, I end up with this:
>>
>>
>>
>> [File: room2.py] -------
>>
>> import clr
>>
>> import abc
>>
>> from PythonAbstractBaseClass import Door
>>
>>
>>
>> class Room(object):
>>
>>     def __init__(self, door):
>>
>>         self.door = door
>>
>>
>>
>>     def open(self):
>>
>>         self.door.open()
>>
>>
>>
>>     def close(self):
>>
>>         self.door.close()
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.door.is_open()
>>
>>
>>
>> class StringDoor(Door):
>>
>>     def __init__(self):
>>
>>         self.status = "closed"
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.status == "open"
>>
>>
>>
>>     def toggle(self):
>>
>>         if self.status == "open":
>>
>>             self.status = "closed"
>>
>>         else:
>>
>>             self.status = "open"
>>
>>
>>
>> class BooleanDoor(Door):
>>
>>     def __init__(self):
>>
>>         self.status = True
>>
>>
>>
>>     def is_open(self):
>>
>>         return self.status
>>
>>
>>
>>     def toggle(self):
>>
>>         self.status = not (self.status)
>>
>>
>>
>> Door.register(StringDoor)
>>
>> Door.register(BooleanDoor)
>>
>> -------
>>
>>
>>
>> But this fails with the following error message:
>>
>>
>>
>>     Door.register(StringDoor)
>>
>> AttributeError: type object 'Door' has no attribute 'register'
>>
>>
>>
>> From what I understood about abc.ABCMeta, this metaclass contributes the
>> ‘register’ method. It seems that abstract C# classes do not come with the
>> same metaclass. They instead come with metaclass “CLR Metatype” which
>> obviously does not provide ‘register’.
>>
>>
>>
>> But if I drop the call to ‘register’, on instantiating one of the derived
>> classes, I receive the error message
>>
>>
>>
>>     sdoor = StringDoor()
>>
>> TypeError: cannot instantiate abstract class
>>
>>
>>
>> Is there a way to inherit from an abstract .NET class or is this is
>> missing feature?
>>
>>
>>
>> Thanks in advance,
>>
>>
>>
>> Henning
>>
>>
>>
>>
>> _________________________________________________
>> Python.NET mailing list - PythonDotNet at python.org
>> https://mail.python.org/mailman/listinfo/pythondotnet
>>
>>
>>
>>
>> _________________________________________________
>> Python.NET mailing list - PythonDotNet at python.org
>> https://mail.python.org/mailman/listinfo/pythondotnet
>>
>>
>>
>> _________________________________________________
>> Python.NET mailing list - PythonDotNet at python.org
>> https://mail.python.org/mailman/listinfo/pythondotnet
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pythondotnet/attachments/20170817/e7d6261d/attachment-0001.html>


More information about the PythonDotNet mailing list