[Python.NET] Inheriting from abstract .NET class

Henning Moeller HMoeller at comprion.com
Mon Sep 26 10:19:27 EDT 2016


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<mailto: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<mailto: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/20160926/5c5625af/attachment-0001.html>


More information about the PythonDotNet mailing list