2

My related question

On the path to enlightenment, I smoked many manuals :)

In the directory 'schemes' we have some files:
'scheme.py'
'scheme_New.py'
'scheme_New2.py'
...

In file 'scheme_New.py' (It's few code for unique case) we have code:

class Scheme:
    def hi(self):
        print('Hi from NEW')

In file 'scheme.py' (It's Main Scheme with a lot of code) we have code:

class Scheme:
    def __new__(cls):
        from schemes.scheme_New import Scheme as NewScheme
        return type('Scheme', (NewScheme, cls), {})
    def hi(self):
        print('Hi from Base Scheme')  

Then i try (any other file):

from schemes.scheme import Scheme
scheme = Scheme()
scheme.hi()

And I get the error:

TypeError: hi() missing 1 required positional argument: 'self'

Why self is not passed?

I want to override the base class 'Scheme' from a file 'scheme.py' with a class with the SAME (important) name from the file 'scheme_New.py' and return it.

Please explain to me why this happens? What am I doing wrong?

It can be done differently, but I want it that way.

I really want to figure this out!
I appreciate all your help.

siroBS
  • 29
  • 3
  • 5
    Why are you returning `return type('Scheme', (NewScheme, cls), {})`? That returns a *new class*, which is a subclass of `Scheme` (confusingly, from *another* unrelated class called `Scheme`). I have no idea what you are even trying to accomplish here, but I don't know why you are returning a new class object from `__new__`. But `self` isn't being passed because your constructor now doesn't return an instance of your class, and `self` is only passed for instances – juanpa.arrivillaga Dec 03 '19 at 23:00
  • 3
    Why are you doing this at all? What was the underlying goal? You've said "I want to override the base class 'Scheme' from a file 'scheme.py' with a class with the SAME (important) name from the file 'scheme_New.py' and return it.", but it's not quite clear what you mean by that, and any reasonable interpretation I can come up with doesn't need anything like the dynamic class creation you've attempted. – user2357112 Dec 03 '19 at 23:35
  • 3
    "It can be done differently, but I want it that way" is the war cry of [the XY problem](https://meta.stackexchange.com/q/66377/322040). Generating a brand new type on *every* call to `__new__` is almost certainly not what you want even if creating a new type was an intended behavior (even if it must generated lazily and on demand, it should be cached so you only create the new type once, on first call, instead of wasting 100x the time and 1+ KB of memory on overhead each time). And it's an insane scheme; why have the base `Scheme` return an instance of a dynamically created subclass at all? – ShadowRanger Dec 03 '19 at 23:43
  • I admit that I got a little lost. I'm just looking for a way to do dynamically: a class Scheme(from scheme_New.py) inherit from Scheme(from scheme.py) and return its instance by the usual way from class Scheme(from scheme.py) – siroBS Dec 04 '19 at 01:10
  • Why not just have `scheme.Scheme` inherit from `scheme_New.Scheme` the normal way? `class Scheme(scheme_New.Scheme)` – user2357112 Dec 04 '19 at 01:57
  • Because, when the class scheme.Scheme is called for instance, it must inherit class scheme_New.Scheme from itself and return the instance of the result, not just its regular instance – siroBS Dec 04 '19 at 09:34
  • Imagine, I can't change `scheme.Scheme` name, the program is working now and files with new schemes in "schemes" directory are generating dynamically. – siroBS Dec 04 '19 at 12:56

1 Answers1

2

I have no idea why you'd want something like this though, but if you insist on doing it like this, it can be done.

Your code was actually quite close. The reason why it doesn't work is that you just return the newly created class object and not an instance of the class, thus there never is an instance (=self) to pass to the hi method.

To fix the issue, you need to simply call object.__new__ with the created type as an argument:

schemes/scheme_New.py:

class Scheme:
    def hi(self):
        print('Hi from NEW')

schemes/scheme.py:

class Scheme:
    def __new__(cls):
        from schemes.scheme_New import Scheme as NewScheme
        created = type('Scheme', (NewScheme, cls), {})
        return object.__new__(created)
    def hi(self):
        print('Hi from Base Scheme')

main.py:

from schemes.scheme import Scheme
scheme = Scheme()
scheme.hi()

Output:

Hi from Base Scheme

Online demo

ruohola
  • 21,987
  • 6
  • 62
  • 97
  • 1
    I've downvoted this because it's probably just driving the questioner further down a wrong path, without helping with the underlying problems. – user2357112 Dec 03 '19 at 23:31
  • Appreciate the honesty. – ruohola Dec 03 '19 at 23:32
  • 1
    @user2357112supportsMonica: An answer that is correct should not be down-voted. – Ethan Furman Dec 04 '19 at 00:37
  • 1
    @EthanFurman: An answer can be unhelpful even if the information contained is correct. – user2357112 Dec 04 '19 at 00:40
  • 1
    I agree with Ethan. I think the answer is still useful though I do think the OP has an XY problem. – Iguananaut Dec 04 '19 at 01:04
  • @Iguananaut I agree that this is for sure a XY problem. – ruohola Dec 04 '19 at 01:05
  • @ruohola, Thanks! This seems to be the best solution but I have a short question: what about comment of **ShadowRanger** in the previous answer? Can this cause any further complex problems? – siroBS Dec 04 '19 at 13:06
  • 2
    @siroBS Yes it can, he has a very valid point, and I don't see either why you'd want to do this this way. But since you already made this question and got an answer to it. I would suggest leaving this as it is for future readers, and possibly making a new question, where you explain your needs much much more clearly. – ruohola Dec 04 '19 at 13:21