pyhon3 dynamically create methods from parent class - python

Let's say I have a class defined like this:
classA():
def do_one():
print("one")
def do_two():
print("two")
def some_other():
print("other")
I want to create a derived class and automatically define every method from the parent class that starts with do
I tried this:
class B(A):
pass
for m in dir(A):
if m[0:3] == "do_":
def dm(self):
print("somebething before")
getattr(super(),m)()
dm.__name__ = m
setattr(B,m,dm)
But i'm getting this error: RuntimeError: super(): __class__ cell not found
Also is there a non-so-hacky/pytonic way of achieving this?

You cannot use super() without arguments outside a class definition. In order to perform lookups super() needs two arguments. Additionally, the definition of dm needs to be wrapped in another function. Otherwise, when it is executed the value of m will be taken from the global scope.
Putting this together, the following should work:
class A():
def do_one(self):
print("one")
def do_two(self):
print("two")
def some_other(self):
print("other")
class B(A):
pass
for m in dir(B):
if m[0:3] == "do_":
def redef(m):
def dm(self):
print("something before")
getattr(super(B, self), m)()
return dm
setattr(B, m, redef(m))
If you run:
x = B()
x.do_one()
x.do_two()
x.some_other()
It will give:
something before
one
something before
two
other

Related

How do I pass attributes of first class to another class inside a class [duplicate]

I have a situation like so...
class Outer(object):
def some_method(self):
# do something
class Inner(object):
def __init__(self):
self.Outer.some_method() # <-- this is the line in question
How can I access the Outer class's method from the Inner class?
You're trying to access Outer's class instance, from inner class instance. So just use factory-method to build Inner instance and pass Outer instance to it.
class Outer(object):
def createInner(self):
return Outer.Inner(self)
class Inner(object):
def __init__(self, outer_instance):
self.outer_instance = outer_instance
self.outer_instance.somemethod()
def inner_method(self):
self.outer_instance.anothermethod()
The methods of a nested class cannot directly access the instance attributes of the outer class.
Note that it is not necessarily the case that an instance of the outer class exists even when you have created an instance of the inner class.
In fact, it is often recommended against using nested classes, since the nesting does not imply any particular relationship between the inner and outer classes.
maybe I'm mad but this seems very easy indeed - the thing is to make your inner class inside a method of the outer class...
def do_sthg(self):
...
def mess_around(self):
outer_class_self = self
class Mooble():
def do_sthg_different(self):
...
outer_class_self.do_sthg()
Plus... "self" is only used by convention, so you could do this:
def do_sthg(self):
...
def mess_around(outer_class_self):
class Mooble():
def do_sthg_different(self):
...
outer_class_self.do_sthg()
It might be objected that you can't then create this inner class from outside the outer class... but this ain't true:
class Bumblebee():
def do_sthg(self):
print "sthg"
def give_me_an_inner_class(outer_class_self):
class Mooble():
def do_sthg_different(self):
print "something diff\n"
outer_class_self.do_sthg()
return Mooble
then, somewhere miles away:
blob = Bumblebee().give_me_an_inner_class()()
blob.do_sthg_different()
even push the boat out a bit and extend this inner class (NB to get super() to work you have to change the class signature of Mooble to class Mooble(object)).
class InnerBumblebeeWithAddedBounce(Bumblebee().give_me_an_inner_class()):
def bounce(self):
print "bounce"
def do_sthg_different(self):
super(InnerBumblebeeWithAddedBounce, self).do_sthg_different()
print "and more different"
ibwab = InnerBumblebeeWithAddedBounce()
ibwab.bounce()
ibwab.do_sthg_different()
later
mrh1997 raised an interesting point about the non-common inheritance of inner classes delivered using this technique. But it seems that the solution is pretty straightforward:
class Fatty():
def do_sthg(self):
pass
class InnerFatty(object):
pass
def give_me_an_inner_fatty_class(self):
class ExtendedInnerFatty(Fatty.InnerFatty):
pass
return ExtendedInnerFatty
fatty1 = Fatty()
fatty2 = Fatty()
innerFattyClass1 = fatty1.give_me_an_inner_fatty_class()
innerFattyClass2 = fatty2.give_me_an_inner_fatty_class()
print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))
I found this.
Tweaked to suite your question:
class Outer(object):
def some_method(self):
# do something
class _Inner(object):
def __init__(self, outer):
outer.some_method()
def Inner(self):
return _Inner(self)
I’m sure you can somehow write a decorator for this or something
related: What is the purpose of python's inner classes?
A few years late to the party.... but to expand on #mike rodent's wonderful answer, I've provided my own example below that shows just how flexible his solution is, and why it should be (or should have been) the accepted answer.
Python 3.7
class Parent():
def __init__(self, name):
self.name = name
self.children = []
class Inner(object):
pass
def Child(self, name):
parent = self
class Child(Parent.Inner):
def __init__(self, name):
self.name = name
self.parent = parent
parent.children.append(self)
return Child(name)
parent = Parent('Bar')
child1 = parent.Child('Foo')
child2 = parent.Child('World')
print(
# Getting its first childs name
child1.name, # From itself
parent.children[0].name, # From its parent
# Also works with the second child
child2.name,
parent.children[1].name,
# Go nuts if you want
child2.parent.children[0].name,
child1.parent.children[1].name
)
print(
# Getting the parents name
parent.name, # From itself
child1.parent.name, # From its children
child2.parent.name,
# Go nuts again if you want
parent.children[0].parent.name,
parent.children[1].parent.name,
# Or insane
child2.parent.children[0].parent.children[1].parent.name,
child1.parent.children[1].parent.children[0].parent.name
)
# Second parent? No problem
parent2 = Parent('John')
child3 = parent2.Child('Doe')
child4 = parent2.Child('Appleseed')
print(
child3.name, parent2.children[0].name,
child4.name, parent2.children[1].name,
parent2.name # ....
)
Output:
Foo Foo World World Foo World
Bar Bar Bar Bar Bar Bar Bar
Doe Doe Appleseed Appleseed John
Again, a wonderful answer, props to you mike!
You can easily access to outer class using metaclass: after creation of outer class check it's attribute dict for any classes (or apply any logic you need - mine is just trivial example) and set corresponding values:
import six
import inspect
# helper method from `peewee` project to add metaclass
_METACLASS_ = '_metaclass_helper_'
def with_metaclass(meta, base=object):
return meta(_METACLASS_, (base,), {})
class OuterMeta(type):
def __new__(mcs, name, parents, dct):
cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct)
for klass in dct.values():
if inspect.isclass(klass):
print("Setting outer of '%s' to '%s'" % (klass, cls))
klass.outer = cls
return cls
# #six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass`
class Outer(with_metaclass(OuterMeta)):
def foo(self):
return "I'm outer class!"
class Inner(object):
outer = None # <-- by default it's None
def bar(self):
return "I'm inner class"
print(Outer.Inner.outer)
>>> <class '__main__.Outer'>
assert isinstance(Outer.Inner.outer(), Outer)
print(Outer().foo())
>>> I'm outer class!
print(Outer.Inner.outer().foo())
>>> I'm outer class!
print(Outer.Inner().outer().foo())
>>> I'm outer class!
print(Outer.Inner().bar())
>>> I'm inner class!
Using this approach, you can easily bind and refer two classes between each other.
I've created some Python code to use an outer class from its inner class, based on a good idea from another answer for this question. I think it's short, simple and easy to understand.
class higher_level__unknown_irrelevant_name__class:
def __init__(self, ...args...):
...other code...
# Important lines to access sub-classes.
subclasses = self._subclass_container()
self.some_subclass = subclasses["some_subclass"]
del subclasses # Free up variable for other use.
def sub_function(self, ...args...):
...other code...
def _subclass_container(self):
_parent_class = self # Create access to parent class.
class some_subclass:
def __init__(self):
self._parent_class = _parent_class # Easy access from self.
# Optional line, clears variable space, but SHOULD NOT BE USED
# IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access.
# del _parent_class
class subclass_2:
def __init__(self):
self._parent_class = _parent_class
# Return reference(s) to the subclass(es).
return {"some_subclass": some_subclass, "subclass_2": subclass_2}
The main code, "production ready" (without comments, etc.). Remember to replace all of each value in angle brackets (e.g. <x>) with the desired value.
class <higher_level_class>:
def __init__(self):
subclasses = self._subclass_container()
self.<sub_class> = subclasses[<sub_class, type string>]
del subclasses
def _subclass_container(self):
_parent_class = self
class <sub_class>:
def __init__(self):
self._parent_class = _parent_class
return {<sub_class, type string>: <sub_class>}
Explanation of how this method works (the basic steps):
Create a function named _subclass_container to act as a wrapper to access the variable self, a reference to the higher level class (from code running inside the function).
Create a variable named _parent_class which is a reference to the variable self of this function, that the sub-classes of _subclass_container can access (avoids name conflicts with other self variables in subclasses).
Return the sub-class/sub-classes as a dictionary/list so code calling the _subclass_container function can access the sub-classes inside.
In the __init__ function inside the higher level class (or wherever else needed), receive the returned sub-classes from the function _subclass_container into the variable subclasses.
Assign sub-classes stored in the subclasses variable to attributes of the higher level class.
A few tips to make scenarios easier:
Making the code to assign the sub classes to the higher level class easier to copy and be used in classes derived from the higher level class that have their __init__ function changed:
Insert before line 12 in the main code:
def _subclass_init(self):
Then insert into this function lines 5-6 (of the main code) and replace lines 4-7 with the following code:
self._subclass_init(self)
Making subclass assigning to the higher level class possible when there are many/unknown quantities of subclasses.
Replace line 6 with the following code:
for subclass_name in list(subclasses.keys()):
setattr(self, subclass_name, subclasses[subclass_name])
Example scenario of where this solution would be useful and where the higher level class name should be impossible to get:
A class, named "a" (class a:) is created. It has subclasses that need to access it (the parent). One subclass is called "x1". In this subclass, the code a.run_func() is run.
Then another class, named "b" is created, derived from class "a" (class b(a):). After that, some code runs b.x1() (calling the sub function "x1" of b, a derived sub-class). This function runs a.run_func(), calling the function "run_func" of class "a", not the function "run_func" of its parent, "b" (as it should), because the function which was defined in class "a" is set to refer to the function of class "a", as that was its parent.
This would cause problems (e.g. if function a.run_func has been deleted) and the only solution without rewriting the code in class a.x1 would be to redefine the sub-class x1 with updated code for all classes derived from class "a" which would obviously be difficult and not worth it.
Do you mean to use inheritance, rather than nesting classes like this? What you're doing doesn't make a heap of sense in Python.
You can access the Outer's some_method by just referencing Outer.some_method within the inner class's methods, but it's not going to work as you expect it will. For example, if you try this:
class Outer(object):
def some_method(self):
# do something
class Inner(object):
def __init__(self):
Outer.some_method()
...you'll get a TypeError when initialising an Inner object, because Outer.some_method expects to receive an Outer instance as its first argument. (In the example above, you're basically trying to call some_method as a class method of Outer.)
Another possibility:
class _Outer (object):
# Define your static methods here, e.g.
#staticmethod
def subclassRef ():
return Outer
class Outer (_Outer):
class Inner (object):
def outer (self):
return _Outer
def doSomething (self):
outer = self.outer ()
# Call your static mehthods.
cls = outer.subclassRef ()
return cls ()
What we can do is pass the self variable of Outer Class inside the Inner Class as Class Argument and Under Outer init initialise the Inner Class with Outer self passed into Inner
class Outer:
def __init__(self):
self.somevalue=91
self.Inner=self.Inner(self)
def SomeMethod(self):
print('This is Something from Outer Class')
class Inner:
def __init__(self,Outer)
self.SomeMethod=Outer.SomeMethod
self.somevalue=Outer.somevalue
def SomeAnotherMethod(self):
print(self.somevalue)
self.SomeMethod()
>>>f=Outer()
>>>f.Inner.SomeAnotherMethod()
91
This is Something from Outer Class
Now After running this function it Works
Expanding on #tsnorri's cogent thinking, that the outer method may be a static method:
class Outer(object):
#staticmethod
def some_static_method(self):
# do something
class Inner(object):
def __init__(self):
self.some_static_method() # <-- this will work later
Inner.some_static_method = some_static_method
Now the line in question should work by the time it is actually called.
The last line in the above code gives the Inner class a static method that's a clone of the Outer static method.
This takes advantage of two Python features, that functions are objects, and scope is textual.
Usually, the local scope references the local names of the (textually) current function.
...or current class in our case. So objects "local" to the definition of the Outer class (Inner and some_static_method) may be referred to directly within that definition.
You may create a class, to decorate inner classes. In this case #inner.
Since this a decorator: Outer.A = inner(Outer.A). Once your code requires Outer.A it will be executed inner.__get__ method, which returns the original class (A) with a new attribute set on it: A.owner = Outer.
A classmethod in class A, in this case def add(cls, y=3), may use new attribute owner at return cls.owner.x + y + 1.
The line setattr(owner, name, self.inner), breaks the descriptor because owner.name => Outer.A => A is no longer an instance of the class inner.
Hope this helps.
class inner:
def __init__(self, inner):
self.inner = inner
def __get__(self, instance, owner):
print('__get__ method executed, only once... ')
name = self.inner.__name__
setattr(self.inner, 'owner', owner)
setattr(owner, name, self.inner) # breaks descriptor
return self.inner #returns Inner
class Outer:
x = 1
#inner
class A:
#classmethod
def add(cls, y=3):
return cls.owner.x + y + 1
print(Outer.A.add(0)) # First time executes inner.__get__ method
print(Outer.A.add(0)) # Second time not necessary.
>> __get__ method executed, only once...
>> 2
>> 2
It can be done by parsing the outer class object into inner class.
class Outer():
def __init__(self,userinput):
self.userinput = userinput
def outer_function(self):
self.a = self.userinput + 2
class Inner():
def inner_function(self):
self.b = self.a + 10
after defining this, it need to run the function
m = Outer(3)
m.outer_function()
print (m.a)
#this will output 5
Now it has the variable of outer class.
and then, it need to run inner class functions.
m.Inner.inner_function(m)
The object m of outer class is parsed into the function of inner class (inside the brackets)
Now, the inner class function is accessing self.a from the outer class.
print (m.b)
#this will output 15
It is too simple:
Input:
class A:
def __init__(self):
pass
def func1(self):
print('class A func1')
class B:
def __init__(self):
a1 = A()
a1.func1()
def func1(self):
print('class B func1')
b = A.B()
b.func1()
Output
class A func1
class B func1

Am I able to call a submethod of a class's attribute from that class using the class as an attribute?

I am very sorry for the confusing title, I did not know how else to phrase the question.
Let's say I have a class, A. It is described as shown:
class A:
def __init__(self, argument):
self.value = argument
def submethod(self, argumentThatWillBeAClass):
print(dir(argumentThatWillBeAClass))
And then I initialize it as shown below:
classAInstance = A('42.0')
Now, I have a class, B. Let's add a submethod that calls A's submethod with B as an argument.
class B:
def __init__(self, argumentThatIsAClassAInstance):
self.classAInstance = argumentThatIsAClassAInstance
def submethod(self):
self.classAInstance.submethod(self)
Let's initialize it with classInstance:
classBInstance = B(classAInstance)
My desired result is that all the attributes of B are printed when B.submethod is called. Is this possible, and if not, how would I achieve something like this?
Now, I have a class, B. Let's add a submethod that calls A's submethod
with B as an argument.
But that isn't what your code does. On the following line:
self.classAInstance.submethod(self)
You are calling the method (I don't know what you mean by "sub" method, these are all just normal methods) with *an instance of B, not B.
Two different ways you could do this:
self.classAInstance.submethod(type(self))
Or:
self.classAInstance.submethod(B)
The semantics aren't exactly the same, since the first dynamically retreives the instance, if some other class inherits from B, it will call dir on that class. The second always prints dir(B), regardless of inheritance.
So:
class A:
def method(self, klass: type) -> None:
print(dir(klass))
class B:
def __init__(self, a: A) -> None:
self.a = a
def method(self) -> None:
self.a.method(type(self))
b = B(A())
As one potential solution, you can use inheritance. This allows class B to inherit everything from class A
class A:
def __init__(self, argument):
self.value = argument
def submethod(self, argumentThatWillBeAClass):
print(dir(argumentThatWillBeAClass))
class B(A):
def __init__(self, value):
super().__init__(value)
def submethod(self, argumentThatWillBeAClass): # You can override the method and do extra code too.
super().submethod(argumentThatWillBeAClass) # Calls A's submethod function

Dynamically adopt the methods of an instance of another class

I have a case, where I have an instance of a class in python which holds instances of other classes. For my use case, I would like a way to use the methods of the "inner" classes from the outer class without referencing the attribute holding the inner class.
I have made a simplistic example here:
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_instance):
self.other_instance= other_instance
def say_good_night(self):
print("Good night")
my_a = A()
my_c = C(other_instance=my_a)
# How to make this possible:
my_c.say_hi()
# Instead of
my_c.other_instance.say_hi()
Class inheritance is not possible, as the object passed to C may be an instance of a range of classes. Is this possible in Python?
I think this is the simplest solution although it is possible with metaprogramming.
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_class):
self.other_class = other_class
C._add_methods(other_class)
def say_good_night(self):
print("Good night")
#classmethod
def _add_methods(cls, obj):
type_ = type(obj)
for k, v in type_.__dict__.items():
if not k.startswith('__'):
setattr(cls, k, v)
my_a = A()
my_c = C(other_class=my_a)
my_c.say_hi()
output :
Hi
First we get the type of passed instance, then we iterate through it's attribute (because methods are attributes of the class not the instance).
If self.other_class is only needed for this purpose, you can omit it as well.
So, because you have done:
my_a = A() and my_c = C(other_class=my_a).
my_c.other_class is the same as my_a asthey point to the same location in memory.
Therefore, as you can do my_a.say_hi() you could also do my_c.other_class.say_hi().
Also, just a note, as you are calling A() before you store it into other_classes, I would probably rename the variable other_classes to class_instances.
Personally, I think that would make more sense, as each of those classes would have already been instantiated.

Can I control the function to call written in the __init__ function?

I want to know if there is a way to control the function call written in the __init__ function of a class ? on an existing framework they have written two function calls inside the __init__ function but I want to call only one, say the first one only. Can I achieve this using Python?
def funA():
print('calling functionA()')
def funB():
print('calling functionB()')
class A():
def __init__(self):
a = funA()
b = funB()
c = A()
Assume I want to call only funA and not B. Can I do that?
I tried referring to the other thead which can skip the __init__ part using helper class, but that does not seem to help me.
Please advise.
You can define a class, which uses A as parent class and overrides its __init__() method as follows:
def funA():
print('calling functionA()')
def funB():
print('calling functionB()')
class A():
def __init__(self):
a = funA()
b = funB()
def othermet(self):
print('calling method of parent class')
class M(A):
def __init__(self):
a = funA()
c = M()
c.othermet()
Out:
calling functionA()
calling method of parent class

Is there a way to share def's between different classes?

I have an application with quite a number of classes. The classes have a number of functions as per def's that are common and obviously some that are not.
Is there a way to define the functions that have common function in one place and be available to a number of classes, or do I have to have at least the def's in every class?
Start by defining the func, which is defined outside.
Then to refer that function in different classes, use the same func inside the classes
def func():
print('func')
class B:
def funcB(self):
print('funcB')
def func(self):
func()
class C:
def funcC(self):
print('funcC')
def func(self):
func()
These can be called now as follows.
b = B()
b.func()
#funcA
b.funcB()
#funcB
c = C()
c.func()
#funcA
c.funcC()
#funcC
As pointed out by Amadan in the comments, class inheritance is a good and consistent way of sharing class objects. Below is an example:
class animals:
def __init__(self):
pass
def has_legs(self, type):
if type == "snake":
print(False)
else:
print(True)
class dog(animals):
def __init__(self):
# This is where the magic happens
animals.__init__(self)
pass
def dog_has_legs(self):
self.has_legs("dog")
bofur = dog()
bofur.dog_has_legs()
bofur.has_legs("snake")
Result:
>>> bofur.dog_has_legs()
True
>>> bofur.has_legs("snake")
False
As you can see, the class dog inherits from animals, and so it can call functions and other objects from the animals class as if they belonged to the dog class.

Categories

Resources