How to convert (inherit) parent to child class? - python

I would like to know how to convert parent object that was return by some function to child class.
class A(object):
def __init__():
pass
class B(A):
def functionIneed():
pass
i = module.getObject() # i will get object that is class A
j = B(i) # this will return exception
j.functionIneed()
I cannot change class A. If I could I would implement functionIneed to class A, but it is impossible because of structure of code.

Python does not support "casting". You will need to write B.__init__() so that it can take an A and initialize itself appropriately.

I have a strong suspicion, nay, conviction, that there is something horribly wrong with your program design that it requires you to do this. In Python, unlike Java, very few problems require classes to solve. If there's a function you need, simply define it:
def function_i_need(a):
"""parameter a: an instance of A"""
pass # do something with 'a'
However, if I cannot dissuade you from making your function a method of the class, you can change an instance's class by setting its __class__ attribute:
>>> class A(object):
... def __init__(self):
... pass
...
>>> class B(A):
... def functionIneed(self):
... print 'functionIneed'
...
>>> a = A()
>>> a.functionIneed()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'functionIneed'
>>> a.__class__ = B
>>> a.functionIneed()
functionIneed
This will work as long as B has no __init__ method, since, obviously, that __init__ will never be called.

You said you want to implement something like this:
class B(A):
def functionIneed():
pass
But really what you would be making is something more like this (unless you had intended on making a class or static method in the first place):
class B(A):
def functionIneed(self):
pass
Then you can call B.functionIneed(instance_of_A). (This is one of the advantages of having to pass self explicitly to methods.)

You did not correctly define your classes.
Should be like this:
class A(object):
def __init__(self):
pass
class B(A):
def __init__(self):
super(B,self).__init__()
def functionIneed(self):
pass
Then you can
j=B()
j.fuctionIneed()
as expected
You forgot to refer to the ins

Just thinking outside the box:
Instead of a new class with the function you want, how about just adding the function to the class or instance you already have?
There is a good description of this in
Adding a Method to an Existing Object Instance

How about:
i = module.getObject() # i will get object that is class A
try:
i.functionIneed()
except AttributeError:
# handle case when u have a bad object
Read up on duck typing.

Related

How to troubleshoot `super()` calls finding incorrect type and obj?

I have a decorator in my library which takes a user's class and creates a new version of it, with a new metaclass, it is supposed to completely replace the original class. Everything works; except for super() calls:
class NewMeta(type):
pass
def deco(cls):
cls_dict = dict(cls.__dict__)
if "__dict__" in cls_dict:
del cls_dict["__dict__"]
if "__weakref__" in cls_dict:
del cls_dict["__weakref__"]
return NewMeta(cls.__name__, cls.__bases__, cls_dict)
#deco
class B:
def x(self):
print("Hi there")
#deco
class A(B):
def x(self):
super().x()
Using this code like so, yields an error:
>>> a = A()
>>> a.x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in x
TypeError: super(type, obj): obj must be an instance or subtype of type
Some terminology:
The source code class A as produced by class A(B):.
The produced class A*, as produced by NewMeta(cls.__name__, cls.__bases__, cls_dict).
A is established by Python to be the type when using super inside of the methods of A*. How can I correct this?
There's some suboptimal solutions like calling super(type(self), self).x, or passing cls.__mro__ instead of cls.__bases__ into the NewMeta call (so that obj=self always inherits from the incorrect type=A). The first is unsustainable for end users, the 2nd pollutes the inheritance chains and is confusing as the class seems to inherit from itself.
Python seems to introspect the source code, or maybe stores some information to automatically establish the type, and in this case, I'd say it is failing to do so;
How could I make sure that inside of the methods of A A* is established as the type argument of argumentless super calls?
The argument-free super uses the __class__ cell, which is a regular function closure.
Data Model: Creating the class object
__class__ is an implicit closure reference created by the compiler if any methods in a class body refer to either __class__ or super.
>>> class E:
... def x(self):
... return __class__ # return the __class__ cell
...
>>> E().x()
__main__.E
>>> # The cell is stored as a __closure__
>>> E.x.__closure__[0].cell_contents is E().x() is E
True
Like any other closure, this is a lexical relation: it refers to class scope in which the method was literally defined. Replacing the class with a decorator still has the methods refer to the original class.
The simplest fix is to explicitly refer to the name of the class, which gets rebound to the newly created class by the decorator.
#deco
class A(B):
def x(self):
super(A, self).x()
Alternatively, one can change the content of the __class__ cell to point to the new class:
def deco(cls):
cls_dict = dict(cls.__dict__)
cls_dict.pop("__dict__", None)
cls_dict.pop("__weakref__", None)
new_cls = NewMeta(cls.__name__, cls.__bases__, cls_dict)
for method in new_cls.__dict__.values():
if getattr(method, "__closure__", None) and method.__closure__[0].cell_contents is cls:
method.__closure__[0].cell_contents = new_cls
return new_cls

Why doesn't the abc.ABCMeta abstract instantiation check work on derivatives of `list` and `dict`?

I have been experimenting a little with the abc module in python. A la
>>> import abc
In the normal case you expect your ABC class to not be instantiated if it contains an unimplemented abstractmethod. You know like as follows:
>>> class MyClass(metaclass=abc.ABCMeta):
... #abc.abstractmethod
... def mymethod(self):
... return -1
...
>>> MyClass()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyClass with abstract methods mymethod
OR for any derived Class. It all seems to work fine until you inherit from something ... say dict or list as in the following:
>>> class YourClass(list, metaclass=abc.ABCMeta):
... #abc.abstractmethod
... def yourmethod(self):
... return -1
...
>>> YourClass()
[]
This is surprising because type is probably the primary factory or metaclass -ish thing anyway or so I assume from the following.
>>> type(abc.ABCMeta)
<class 'type'>
>>> type(list)
<class 'type'>
From some investigation I found out that it boils down to something as simple as adding an __abstractmethod__ attribute to the class' object and rest happens by itself:
>>> class AbstractClass:
... pass
...
>>> AbstractClass.__abstractmethods__ = {'abstractmethod'}
>>> AbstractClass()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class AbstractClass with abstract methods abstractmethod
So one can simply avoid the check by intentionally overriding the __new__ method and clearing out __abstractmethods__ as in below:
>>> class SupposedlyAbstractClass(metaclass=abc.ABCMeta):
... def __new__(cls):
... cls.__abstractmethods__ = {}
... return super(AbstractClass, cls).__new__(cls)
... #abc.abstractmethod
... def abstractmethod(self):
... return -1
...
>>> SupposedlyAbstractClass()
<__main__.SupposedlyAbstractClass object at 0x000001FA6BF05828>
This behaviour is the same in Python 2.7 and in Python 3.7 as I have personally checked. I am not aware if this is the same for all other python implementations.
Finally, down to the question ... Why has this been made to behave like so? Is it wise we should never make abstract classes out of list, tuple or dict? or should I just go ahead and add a __new__ class method checking for __abstractmethods__ before instantiation?
The problem
If you have the next class:
from abc import ABC, abstractmethod
class Foo(list, ABC):
#abstractmethod
def yourmethod(self):
pass
the problem is that and object of Foo can be created without any error because Foo.__new__(Foo) delegates the call directly to list.__new__(Foo) instead of ABC.__new__(Foo) (which is responsible of checking that all abstract methods are implemented in the class that is going to be instantiated)
We could implement __new__ on Foo and try to call ABC.__new__:
class Foo(list, ABC):
def __new__(cls, *args, **kwargs):
return ABC.__new__(cls)
#abstractmethod
def yourmethod(self):
pass
Foo()
But he next error is raised:
TypeError: object.__new__(Foo) is not safe, use list.__new__()
This is due to ABC.__new__(Foo) invokes object.__new__(Foo) which seems that is not allowed when Foo inherits from list
A possible solution
You can add additional code on Foo.__new__ in order to check that all abstract methods in the class to be instantiated are implemented (basically do the job of ABC.__new__).
Something like this:
class Foo(list, ABC):
def __new__(cls, *args, **kwargs):
if hasattr(cls, '__abstractmethods__') and len(cls.__abstractmethods__) > 0:
raise TypeError(f"Can't instantiate abstract class {cls.__name__} with abstract methods {', '.join(cls.__abstractmethods__)}")
return super(Foo, cls).__new__(cls)
#abstractmethod
def yourmethod(self):
return -1
Now Foo() raises an error. But the next code runs without any issue:
class Bar(Foo):
def yourmethod(self):
pass
Bar()

suppress calling __init__() of parent class

I just noticed some unintended behaviour then tested it in an interpretor (Python 3.5.3):
>>> class SomeClass:
... def __init__(self):
... print("nothing important")
...
>>> a = SomeClass()
nothing important
>>> class SomeOtherClass(SomeClass):
... pass
...
>>> b = SomeOtherClass()
nothing important
>>>
I thought you needed to directly call the parents __init__(). What is the simplest way to write or instantiate the child class such that it does not run the __init__() from the parent class?
You can by defining an __init__ method in the child class:
class SomeOtherClass(SomeClass):
def __init__(self):
pass
I want some methods from the parent, just not that the init runs
Then your design is wrong. If you only care about code reuse but not proper subtyping (as defined by Liskov), proper designs are either composition/delegation or (probably the best in your case) multiple inheritance with mixin classes:
class CommonMixin():
def method1(self):
pass
def method2(self):
pass
class SomeClass(CommonMixin, SomeBaseClass):
def __init__(self):
print("nothing important")
class SomeOtherClass(CommonMixin, SomeOtherBaseClass):
pass

how to solve attribute error when all attributes do exist?

I am writing a program for my A level course in python and i need to access an attribute from one class in to another using inheritance. here is an example of what I am trying to do.
class class1():
def __init__(self):
self.testValue = 'hello'
class class2(class1):
def __init__(self):
self.inheritedValue = class1.testValue
print(self.inheritedValue)
object = class2()
when running this code i get the following attribute error.
AttributeError: type object 'class1' has no attribute 'testValue'
anyone got a solution for this??
First a comment to code style: class names are written in CamelCase, so name them Class1 and Class2.
Secondly, your class Class1 doesn't have the said attribute, but each instance does.
So your class2 should look like
class Class2(Class1):
def __init__(self):
super().__init__() # now we have everything Class1 provides us with
self.inheritedValue = self.testValue
print(self.inheritedValue)
because each object of Class2 is also an object of Class1
The attribute does not exist within the scope of class2 the way you've implemented it. By passing it in the class definition, it is inherited but the attribute doesn't exist yet. That is, unless you've called the constructor. Two ways of doing this, by either using the super built-in function(not recommended in real life, see here, it's a nice read. Anyway, here are a few solutions:
class class1():
def __init__(self):
self.testValue = 'hello'
class class2(class1):
def __init__(self):
class1.__init__(self)
print(self.testValue)
obj = class2()
if you do not want to call the constructor of the class you are inheriting, you could do something like this:
class class1():
testValue = 'hello'
def __init__(self):
pass
class class2(class1):
def __init__(self):
self.inheritedValue = class1.testValue
print(self.inheritedValue)
obj = class2()
Side note, object is a built-in so you shouldn't use it.

Python: set class method as class attribut

The following seems not to be valid in python 3:
class A:
callback = A.callback_function
def callback_function(self):
pass
You'll get an error saying type 'A' is not defined. Is it because 'A' cannot be refered to in it self? Is there anyway I can achieve this type of functionality?
What I'm trying to do is something like this: I have a base class:
class Base:
callback = Base.ignore
def ignore(self):
pass
def some_other_function(self):
self.callback()
In a subclass I'd like to set another callback function:
class Derived(Base):
callback = Derived.special_function
def special_function(self):
do_stuff()
Well, you can just name your function callback, and it'll be just the same, but if you really insist on this way:
class A:
def callback_function(self): pass
callback = callback_function

Categories