Class method as a decorator - python

I have a class where I have multiple methods. I want to use one of the methods as a decorator for other methods. For this I am using following syntax:
#self.action
def execute(self,req):
where action is other method in my class. But it doesn't work and throws exception as
name 'self' is not defined

You cannot use a method of the class while defining it; there is no self within the class nor is the class 'baked' yet to even access any class.
You can treat methods as functions to use as a decorator:
class SomeClass():
def action(func):
# decorate
return wrapper
#action
def execute(self, req):
# something
If action is defined on a base class, then you'd have to refer to the name via the base class:
class Base():
#staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
#Base.action
def execute(self, req):
# something
For Python 2, you'd have to make action a static method here, as otherwise you get an unbound method that'll complain you cannot call it without an instance as the first argument. In Python 3, you can leave off the #staticmethod decorator there, at least for the purposes of the decorator.
But note that action cannot then be used as a method directly; perhaps it should not be part of the class at all at that point. It is not part of the end-user API here, presumably the decorator is not used by consumers of the instances of these classes.

Just beware that both the decorator and the decorated function are unbound methods, so you can only access the self (or cls for classmethods) in the inner scope of the decorator, and must manually bind the decorated method to the instance bound in the inner decorator.
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate
def func(self):
return self.y
A().func() # 30!!
Still trying to wrap my head around how decorators could be inherited and overridden.
Beware that for the decorator to work it can't be bound to an instance. That is: there is no way to make this work
a = A()
#a.decorate
def func(*args):
return 1
Despite this pattern is much more common than the asked here.
At this point the question raises: is it a method at all or just code that you happen to hide in a class?
The only way to prevent the decorator being wrongfully bound is to declare it as a staticmethod, but then it must be in a previous super class because to be used it must be bound to the static class reference which would not be yet defined, just as the self.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
class B(A):
#A.decorate
def func(self):
return 1
class C():
x = 2
#B.decorate
def func(self):
return 1
a = A()
class D():
x = 3
#a.decorate
def func(self):
return 1
B().func() # 1
C().func() # 2
D().func() # 3
But as you can see, there is no way for the decorator to use the state of its own class. class A from this last example just happens to be a mixin with a default x variable and an "unrelated" static decorator.
So, again, is it a method?
To overcome all of this, you can bind the staticmethod in your same class to an arbitrary type. Namely, the builtin type will do.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate.__get__(type)
def func(self):
return 1
class B:
x = 2
#A.decorate
def func(self):
return 1
class C:
x = 3
#(A().decorate) # Only for Python 3.9+, see PEP-614
def func(self):
return 1
A().func() # 1
B().func() # 2
C().func() # 3
But this features too much magic for my taste. And still not a method for my gut.

In python "self" is passed to instance methods as an argument (the first), "self" is just a convention is possible to call it "foobarbaz" (of course it would be silly)… the point is that, from the outside "self" is not defined (because its scope is the method)… you can't decorate class methods with other class methods, instead you have to write a separate class!

Related

Access attribute of outer class from nested 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

Maintaining staticmethod calls if class is renamed

I have a class with a static method which is called multiple times by other methods. For example:
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
def two(self):
return 2 * A.one()
def three(self):
return 3 * A.one()
Method one is a utility function that belongs inside the class but isn't logically an attribute of the class or the class instance.
If the name of the class were to be changed from A to B, do I have to explicitly change every call to method one from A.one() to B.one()? Is there a better way of doing this?
I pondered this question once upon a time and, while I agree that using a refactoring utility is probably the best way to go, as far as I can tell it is technically possible to achieve this behaviour in two ways:
Declare the method a classmethod.
Use the __class__ attribute. Leads to rather messy code, and may well be deemed unsafe or inefficient for reasons I am not aware of(?).
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
#classmethod
def two(cls):
return 2 * cls.one()
def three(self):
return 3 * self.__class__.one()
a = A()
print(a.two())
print(a.three())

define a decorator as method inside class

I'm trying to create a method inside my class that counts the complete run of a specific function. I want to use a simple decorator. I found this reference and rewrite this simple script:
class myclass:
def __init__(self):
self.cnt = 0
def counter(function):
"""
this method counts the runtime of a function
"""
def wrapper(self, **args):
function(**args)
self.counter += 1
return wrapper
#myclass.counter
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
# or if comment #myclass.counter
# somefunc = myclass.counter(somefunc)
somefunc()
And of course, I get:
TypeError: wrapper() missing 1 required positional argument: 'self'
I tried to rewrite the counter as a class method:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self, function):
"""
this method counts the runtime of a function
"""
def wrapper(**args):
function(**args)
self.cnt += 1
return wrapper
def somefunc():
print("hello from somefunc")
if __name__ == "__main__":
obj = myclass()
somefunc = obj.counter(somefunc)
for i in range(10):
somefunc()
print(obj.cnt)
Which works fine but I think it is not a valid decorator definition. Is there any way to define the decorator inside the class method and pass the self-argument to its function? or defining a decorator inside a class is useless?
EDIT:------
First I can't define the decoration outside of the class method. Second I'm trying to make a scheduled class that runs a specific function (as input) for a fixed interval and a specific amount of time so I need to count it.
So I was able to draft up something for you, below is the code:
def count(func):
def wrapper(self):
TestClass.call_count += 1
func(self)
return wrapper
class TestClass(object):
call_count = 0
#count
def hello(self):
return 'hello'
if __name__ == '__main__':
x = TestClass()
for i in range(10):
x.hello()
print(TestClass.call_count)
Why would it cause problems to have the decorator in a class:
It's not straight forward to have a decorator function inside the class. The reasons are below:
Reason 1
Every class method must take an argument self which is the instance of the class through which the function is being called. Now if you make the decorator function take a self argument, the decorator call #count would fail as it get converted to count() which doesn't pass the self argument and hence the error:
TypeError: wrapper() missing 1 required positional argument: 'self'
Reason 2
Now to avoid that you can make your decorator as static by changing the declaration like below:
#staticmethod
def count(func):
pass
But then you have another error:
TypeError: 'staticmethod' object is not callable
Which means you can't have a static method as well. If you can't have a static method in a class, you have to pass the self instance to the method but if you pass the self instance to it, the #count decorator call wouldn't pass the self instance and hence it won't work.
So here is a blog that explains it quite well, the issues associated with it and what are the alternatives.
I personally prefer the option to have a helper class to hold all my decorators that can be used instead of the only class in which it's defined. This would give you the flexibility to reuse the decorators instead of redefining them which would follow the ideology
code once, reuse over and over again.
Your second code example is functionally equivalent to a standard decorator. The standard decorator syntax is just a shorthand for the same thing, namely, reassigning a function value equal to a closure (a function pointer with arguments predefined), where the closure is your decorator wrapper holding the original as its predefined argument.
Here's an equivalent with standard syntax. Notice you need to create the counter class instance in advance. The decorator syntax refers to that instance, because it must indicate the specific object which holds your counter, rather than just the class of the object:
class myclass:
def __init__(self):
self.cnt = 0
def counter(self,function):
"""
this method counts the number of runtime of a function
"""
def wrapper(**args):
function(self,**args)
self.cnt += 1
return wrapper
global counter_object
counter_object = myclass()
#counter_object.counter
def somefunc(self):
print("hello from somefunc")
if __name__ == "__main__":
for i in range(10):
somefunc()
print(counter_object.cnt)

Mocking a class method and changing some object attributes in Python

I am new to mock in Python. I want to know how to replace (mock) a class method while testing with another one, knowing that the original just changes some attributes of self without returning any value. For example:
def some_method(self):
self.x = 4
self.y = 6
So here I can't just change the return_value of the mock. I tried to define a new function (that should replace the original) and give it as side_effect to the mock. But how can I make the mocking function change attributes of the object in the class.
Here is my code:
#patch('path.myClass.some_method')
def test_this(self,someMethod):
def replacer(self):
self.x = 5
self.y = 16
some_method.side_effect = replacer
So how does Python now understands the self argument of replacer? Is that the self of the test class, or the self as the object of the class under test?
Apologies in advance if I don't understand what you are trying to do, but I think this might work:
import unittest
from unittest.mock import patch
class MyClass:
def __init__(self):
self.x = 0
self.y = 0
def some_method(self):
self.x = 4
self.y = 6
class OtherClass:
def other_method(self):
self.x = 5
self.y = 16
class MyTestClass(unittest.TestCase):
#patch('__main__.MyClass.some_method', new=OtherClass.other_method)
def test_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
def test_not_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 4)
self.assertEqual(a.y, 6)
if __name__ == "__main__":
unittest.main()
This replaces some_method() with other_method() when patched, which sets different values for attributes x, y, and when the test is run, it gives the results:
..
----------------------------------------------------------------------
Ran 2 tests in 0.020s
OK
EDIT: to answer question about how to do inside the test function without mocking a class...
def test_inside_patch(self):
def othermethod(self):
self.x = 5
self.y = 16
patcher = patch('__main__.MyClass.some_method', new=othermethod)
patcher.start()
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
patcher.stop()
Make sure you call start() and stop() on the patcher otherwise you can get into a situation where the patch is active and you don't want it to be. Note that to define the mock function inside the test code function, I didn't use patch as a decorator, because the mock function has to be defined before using the 'new' keyword in patch. If you want to use patch as a decorator you have to define the mock function someplace before the patch, defining it inside of MyTestClass also works, but it seems you really want to have the mock function defined inside your test function code.
EDIT: added summary of 4 ways I see to do this...
# first way uses a class outside MyTest class
class OtherClass:
def other_method(self):
...
class MyTest(unittest.TestCase):
#patch('path_to_MyClass.some_method', new=OtherClass.other_method)
def test_1(self)
...
# 2nd way uses class defined inside test class
class MyOtherClass:
def other_method(self):
...
#patch('path_to_MyClass.some_method', new=MyOtherClass.other_method)
def test_2(self):
...
# 3rd way uses function defined inside test class but before patch decorator
def another_method(self):
...
#patch('path_to_MyClass.some_method', new=another_method)
def test_3(self):
...
# 4th way uses function defined inside test function but without a decorator
def test_4(self):
def yet_another_method(self):
...
patcher = patch('path_to_MyClass.some_method', new=yet_another_method)
patcher.start()
...
patcher.stop()
None of these uses a side_effect, but they all solve the problem of mocking a class method and changing some attributes. Which one you choose depends on the application.

How to access outer class from an inner class?

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

Categories