Python object hierarchy; Referencing an owner instance? - python

Is there no magic python way of accessing the instance of the class that has a reference to the current self inside it?
ie:
class A(object):
def __init__(self):
self.B = B()
def say_hi(self):
print "Hi"
class B(object)
def __init__(self):
__get_owner_ref__.say_hi()
A()
get_owner_ref being the magic bullet that does not exist.
Is there a feature in python for this behaviour?
Yes I know I could pass a reference in to the constructor, but I'm looking for a more elegant solution.

No, You'd have to do something like this
class A(object):
def __init__(self):
self.B = B(parent=self)
def say_hi(self):
print "Hi"
class B(object)
def __init__(self, parent):
self.parent = parent # you don't need to do this, but it might be a good idea
parent.say_hi()
A()

On the second thought, what you're looking for pretty closely resembles descriptors. Consider:
class Agent(object):
def __get__(self, obj, objtype):
print 'Agent %s called from %s ' % (id(self), obj.name)
class X(object):
agent = Agent()
def __init__(self, name):
self.name = name
a = X('Foo')
a.agent
b = X('Bar')
b.agent
Here the agent is attached to two different instances and "knows" each time which instance wants to talk to him.

No, there is no nice way of doing this. Pass a reference in to the initializer.
To preclude questions, it's probably possible in most cases to find the owner heuristically by inspecting the stack, something like in this question. But it will be fragile, buggy and difficult to understand. And it goes against the "explicit > implicit" philosophy.

As far as I know such a feature does not exist. Also, passing it in as reference to the constructor and calling self.parent.say_hi() is much more explicit and (indeed) elegant. And explicit is better than implicit or using magic language features.

Technically, you can use sys._getframe:
class B(object):
def __init__(self):
import sys
a = sys._getframe(1).f_locals['self']
a.say_hi()
But you should not do that. It's bound to lead to confusion, will break on new Python implementations, will complicate debugging, and is prone to break.There's a reason why sys._getframe is listed in 5 Years of Bad Ideas.
Instead, pass a reference, either to the parent object, or to the say_hi method.

Related

Refer to a superclass from the class body

I've got some code where I need to refer to a superclass when defining stuff in a derived class:
class Base:
def foo(self):
print('foo')
def bar(self):
print('bar')
class Derived_A(Base):
meth = Base.foo
class Derived_B(Base):
meth = Base.bar
Derived_A().meth()
Derived_B().meth()
This works, but I don't like verbatim references to Base in derived classes. Is there a way to use super or alike for this?
You can't do that.
class keyword in Python is used to create classes which are instances of type type. In it's simplified version, it does the following:
Python creates a namespace and executes the body of the class in that namespace so that it will be populated with all methods and attributes and so on...
Then calls the three-arguments form of type(). The result of this call is your class which is then assign to a symbol which is the name of your class.
The point is when the body of the class is being executed. It doesn't know about the "bases". Those bases are passed to the type() after that.
I also explained the reasons why you can't use super() here.
Does this work for you?
class Base:
def foo(self):
print('foo')
def bar(self):
print('bar')
class Derived_A(Base):
def __init__(self):
self.meth = super().foo
class Derived_B(Base):
def __init__(self):
self.meth = super().bar
a = Derived_A().meth()
b = Derived_B().meth()
You'll need to lookup the method on the base class after the new type is created. In the body of the class definition, the type and base classes are not accessible.
Something like:
class Derived_A(Base):
def meth(self):
return super().foo()
Now, it is possible to do some magic behind the scenes to expose Base to the scope of the class definition as its being executed, but that's much dirtier, and would mean that you'd need to supply a metaclass in your class definition.
Since you want "magic", there is still one sane option we can take before diving into metaclasses. Requires Python 3.9+
def alias(name):
def inner(cls):
return getattr(cls, name).__get__(cls)
return classmethod(property(inner))
class Base:
def foo(self):
...
class Derived_A(Base):
meth = alias("foo")
Derived_A().meth() # works
Derived_A.meth() # also works
Yes, this does require passing the method name as a string, which destroys your IDE and typechecker's ability to reason about it. But there isn't a good way to get what you are wanting without some compromises like that.
Really, a bit of redundancy for readability is probably worth it here.

Python - Refactor similar methods found in different classes

I'm in scenario where I want to refactor several classes which have identical and/or similar methods. The number of class are around ~20 and the number of similar methods are around ~15. All sorts of combinations exist within this space, which is why I'm a bit reluctant to using inheritance to solve this issue (rightfully?).
The code is part of a wrapper around another application that is controlled by a com api. The wrapper in turn is part of a package that is distributed internally at the company where I work. Therefore the interfaces of the classes have to remain the same (for backwards compatibility).
This example illustrates some very simplified versions of the classes:
class FirstCollectionLike:
def __init__(self):
self._collection = list()
def add(self, arg):
self._collection.append(arg)
def remove(self, index):
del self._collection[index]
class SecondCollectionLike:
def __init__(self):
self._collection = list()
self._resource = some_module.get_resource()
def start(self):
some_module.start(self.resource)
def add(self, arg):
self._collection.append(arg)
def remove(self, value):
self._collection.remove(value)
class SomeOtherClass:
def __init__(self):
self._some_attribute = 0
self._resource = some_module.get_resource()
def add(self, value):
self._some_attribute += value
def start(self):
some_module.start(self._resource)
Are there any design patterns I could look into that would help me solve this issue?
My initial thought was to create method classes like Add, RemoveByIndex and RemoveByName that implements __call__ like so:
class Add:
def __init__(self, owner):
self.owner = owner
def __call__(self, item):
self._collection.append(item)
class AddAndInstantiate:
def __init__(self, owner, type_to_instantiate):
self.owner = owner
self.type_to_instantiate = type_to_instantiate
def __call__(self, name):
self._collection.append(type_to_instantiate(name))
and then assign instances of those classes as instance attributes to their respective owner objects:
class RefactoredClassOne:
def __init__(self):
self.add = Add(self)
self.remove = RemoveByIndex(self)
class RefactoredClassTwo:
def __init__(self):
self.add = AddAndInstantiate(self, SomeClass)
self.remove = RemoveByName(self)
This way I could quite easily add any method I want to a class and provide some arguments to the method class if needed (like the type of the class to instantiate in the example above). The downside is that it is a bit harder to follow what is happening, and the automatic documentation generation we use (sphinx) does not work if the methods are implemented in this way.
Does this seem like a bad approach? What are the alternatives?
First, if your classes are as simple as you example suggest, I'm not sure OOP is the right tool. What your classes are doing is just renaming a couple of basic calls. This is useless abstraction and IMO a bad practice (why force me to look to into the SecondClassCollectionLike.py file to discover that .add() is 1) in fact a wrongly named append and 2) that my collection is in fact a listwith a fancy name?)
In that case I'd say that a functional approach might be better, and a workflow such as:
a = SecondClassCollectionLike()
a.add("x")
a.add("y")
a.remove(0)
a.start()
would be a lot clearer if it looked like
a = list()
a.append("x")
a.append(y)
del a[0]
somemodule.start()
If your classes are in fact more complex and you really want to keep the OOP approach, I think that this solution is probably close to your solution and what you're looking for.
The idea is to have modules which hold the logic. For example a _collection_behaviour.py module, which holds the add(), remove(), increment() or whatever. And a _runtime.py module, which holds that start(), stop(), etc. logic.
This way you could have classes which exibit behaviour from these modules:
calss MyClass():
def __init__(self):
self._collection = list()
from ._collection_behaviour import add
from ._collection_behaviour import remove
from ._runtime import start
But I do not see the point in making these functions classes which implement __call__ if that's all they do.

Python v2 nested subclass "global name '<ClassName>' is not defined"

First off, let me say that yes I have researched this extensively for a few days now with no luck. I have looked at numerous examples and similar situations such as this one, but so far nothing has been able to resolve me issue.
My problem is I have a Python project that has a primary class, with two nested classes (yea yea I know), one of those classes is a subclass of the first. I can not figure out why I keep getting NameError: global name 'InnerSubClass' is not defined.
I understand scoping (both classes in question are in the same scope) but nothing I try seems to resolve the issue (I want to keep the two classes nested at a minimum) despite this problem working for other people.
Here is a simple example of what I am trying to do:
class SomeClass(object):
def __init__(self):
"""lots of other working stuff"""
class MainClass(object):
def __init__(self):
self.stuff = []
self.moreStuffs = []
class InnerClass(object):
def __init__(self, thing, otherThing):
self.thing = thing
self.otherThing = otherThing
self.otherStuff = []
class InnerSubClass(InnerClass):
def __init__(self, thing, otherThing, newThing):
super(InnerSubClass).__init__(thing, otherThing)
self.newThing = newThing
"""other code that worked before the addition of 'InnerSubClass'"""
def doSomething(self):
innerclass = self.InnerSubClass('thisthing', 'thatthing', 'thingthing')
print("just more thing words %s" % innerclass.newThing)
myThing = MainClass()
myThing.doSomething()
I have tried changing super(InnerSubClass).__init__(thing, otherThing)
to
super(InnerClass.InnerSubClass).__init__(thing, otherThing)
and even
super(MainClass.InnerClass.InnerSubClass).__init__(thing, otherThing) with no success. I made "InnerSubClass" inherit straight from object InnerSubClass(object): etc, and it still doesn't work.
Granted I am far from a seasoned python developer and come from mostly other compiled OO languages, and can't seem to wrap my head around why this isn't working. If I get rid of the "InnerSubClass", everything works just fine.
It doesn't seem like python offers "private" classes and functions like other languages, which is fine but I would like to utilize the nesting to at least keep objects "lumped" together. In this case, nothing should be instantiating "InnerClass" or "InnerSubClass" except functions in "MainClass".
Please provide helpful advice and explain why it doesn't work as expected with background information on how this should be done properly. If this was as simple as it seems, it would have been figured out by now.
edit: for clarification, this is only for v2
There is no "class scope" in lookup order
When creating a new class, the code in the body is executed and the resulting names are passed to type for creation. Python lookups go from inner to outer, but you don't have a "class level", only the names you define to become attributes/methods of your new class. In fact, if you want to access class variables inside a method, you use MyClass.attr instead of simple attr.
The inheritance works because InnerSubClass(InnerClass) occurs inside the class creation. To access InnerClass after MainClass has been created, do the same as you would for class attributes: MainClass.InnerClass
Just to include an example:
class Outer:
out = 1
class Inner:
inside = 2
try:
print(out) # this is confusing
except NameError:
print("can't find out")
def f(self):
try:
print(inside) # this is clear
except NameError:
print("can't find inside")
try:
print(Inner.inside) # this is less clear
except NameError:
print("can't find Inner.inside")
Outer.Inner().f()
# can't find anything
Edit:
The above is a general view, to apply it directly to your situation, look at your inner classes the way you look at regular class attributes. You'd access these as MyClass.attr, where MyClass is defined globally. If you replace attr with InnerSubClass, you get the class (attribute lookup doesn't care about inheritance, but about where the attributes are).
A stripped-down example with nested inheriting classes:
class MainClass(object):
class Inner(object):
pass
class InnerSub(Inner):
def __init__(self):
print(super(MainClass.InnerSub)) # note you use MainClass, known globally
def f(self):
return self.InnerSub()
MainClass().f() # prints "<super ...>" and returns a MainCLass.InnerSub object
Here they do it like this
super(MainClass.InnerSubClass, self).__init__(thing, otherThing)
So that you can test it here is the full working example
class SomeClass(object):
def __init__(self):
"""lots of other working stuff"""
class MainClass(object):
def __init__(self):
self.stuff = []
self.moreStuffs = []
class InnerClass(object):
def __init__(self, thing, otherThing):
self.thing = thing
self.otherThing = otherThing
self.otherStuff = []
class InnerSubClass(InnerClass):
def __init__(self, thing, otherThing, newThing):
super(MainClass.InnerSubClass, self).__init__(thing, otherThing)
self.newThing = newThing
"""other code that worked before the addition of 'InnerSubClass'"""
def doSomething(self):
innerclass = self.InnerSubClass('thisthing', 'thatthing', 'thingthing')
print("just more thing words %s" % innerclass.newThing)
print("and I also inherit from InnerClass %s" % innerclass.otherThing)
myThing = MainClass()
myThing.doSomething()
The output is
just more thing words thingthing
and I also inherit from InnerClass thatthing
If you have reasons for not using MainClass.InnerSubClass, you can also use type(self) or self.__class__ (OK, but which one) inside __init__ to get the containing class. This works well lots of layers deep (which shouldn't happen anyway), and requires the argument passed to super to be the type of the instance (which it should be anyway) but breaks if you subclass, as seen here. The concept might be clearer to you than scoping rules:
class MainClass:
class Inner:
pass
class InnerSub(Inner):
def __init__(self):
print(super(self.__class__))
print(super(type(self)))
MainClass().InnerSub()

How to pass a class method as an argument to a function external to that class?

This is how it works for me:
class SomeName:
def __init__(self):
self.value = "something"
def some_method(self):
print self.value
def external_func(instance, method):
method(instance)
external_func(SomeName(), SomeName.some_method)
This appears to work correctly. Is this the right way to do this?
Your code is "technically correct" (it does what you ask for) but - at least in your example - pretty useless:
def external_func(instance, method):
method(instance)
external_func(SomeName(), SomeName.some_method)
is the same as:
def external_func(method):
method()
external_func(SomeName().some_method)
which FWIW is the same as:
SomeName().some_method()
but I assume you understood this already .
Now you probably have a reason to try to pass both the method AND instance to external_func(), or there might be a better way to solve your real problem...
I of course don't know what you're doing exactly, but it sounds to me like you're trying to do too much inside of one function. Your problem might be better solved by simply splitting up the contents of external_func.
The goals here, as I understand them, are you don't know ahead of time what the object/method pair will be, and want to reduce code repetition.
Perhaps something like this would be better:
def main():
obj = SomeName()
# do the setting up portion
complex_object = external_func_set_up(obj)
# presumably at some point you have to designate the method to be used:
method = get_method_name(obj)
# run the method:
getattr(obj, method)()
# finish up the external operation:
external_func_complete(***args***)
I understand this is more code, but I think in the end it's a lot clearer what is happening, and also might force you to think through your problem a bit more (and potentially come up with an even better solution).
You could pass SomeName().some_method or make some_metod staticmethod or classmethod if there is no instance data used in your method.
Check documentation to know more about staticmethod and classmethod:
https://docs.python.org/3/library/functions.html#staticmethod
https://docs.python.org/3/library/functions.html#classmethod
Depending on what you're doing. Because functions are also objects in Python it is possible to do so.
But is it a good solution? It seems though that you're trying to handle a problem which maybe could be better solved with more of an object oriented approach:
class A:
def __init__(self):
self.value = "class A"
def some_method(self):
print self.value
class B:
def __init__(self):
self.value = "class B"
def some_method(self):
print self.value
some_class = A()
some_class.some_method()
some_class = B()
some_class.some_method()
Output:
"class A"
"class B"
In my view this would be a better approach (if this is possible/reasonable in your case): You just call some_method() on your class, maybe without even knowing what exact type of object you're dealing with (regarding inheritance). The class itself knows what to do and reacts accordingly when its method has been called.
This of course doesn't work when you work with external libraries which you have no influence on.

Possible to return instantiator in Python?

class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
I know this isn't proper encapsulation but for interest's sake...
Given a "Parent" class that instantiates a "Child" object, is it possible from within Child to return the Parent object that instantiated it? And if no, I'm curious, do any languages support this?
To answer the question, no, there's no way1 the child instance knows about any classes which contain references to it. The common2 way to handle this is:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
1 Of course, this isn't strictly true. As another commentor noted, you can extract the stack frame from the executing code within the __init__ method, and examine the f_locals dictionary for the self variable for the frame before the currently executing one. But this is complicated, and prone to error. Highly unrecommended.
2 A slightly better way to handle this (depending on the specific needs of the program) might be to require the parent to pass itself to the child, like so:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
Here's a reasonably-simple metaclass solution to the problem:
import functools
class MetaTrackinits(type):
being_inited = []
def __new__(cls, n, b, d):
clob = type.__new__(cls, n, b, d)
theinit = getattr(clob, '__init__')
#functools.wraps(theinit)
def __init__(self, *a, **k):
MetaTrackinits.being_inited.append(self)
try: theinit(self, *a, **k)
finally: MetaTrackinits.being_inited.pop()
setattr(clob, '__init__', __init__)
def Instantiator(self, where=-2):
return MetaTrackinits.being_inited[where]
setattr(clob, 'Instantiator', Instantiator)
return clob
__metaclass__ = MetaTrackinits
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
self.parent = self.Instantiator()
p = Parent()
print p
print p.child.parent
a typical output, depending on the platform, will be something like
<__main__.Parent object at 0xd0750>
<__main__.Parent object at 0xd0750>
You could obtain a similar effect (in 2.6 and later) with a class decorator, but then all classes needing the functionality (both parent and children ones) would have to be explicitly decorated -- here, they just need to have the same metaclass, which may be less intrusive thanks to the "module-global __metaclass__ setting" idiom (and the fact that metaclasses, differently from class-decorations, also get inherited).
In fact, this is simple enough that I would consider allowing it in production code, if the need for that magical "instantiator" method had a proven business basis (I would never allow, in production code, a hack based on walking the stack frames!-). (BTW, the "allowing" part comes from the best-practice of mandatory code reviews: code changes don't get into the trunk of the codebase without consensus from reviewers -- this how typical open source projects work, and also how we always operate at my employer).
Here's an example based off of some of Chris B.'s suggestions to show how absolutely terrible it would be to inspect the stack:
import sys
class Child(object):
def __init__(self):
# To get the parent:
# 1. Get our current stack frame
# 2. Go back one level to our caller (the Parent() constructor).
# 3. Grab it's locals dictionary
# 4. Fetch the self instance.
# 5. Assign it to our parent property.
self.parent = sys._getframe().f_back.f_locals['self']
class Parent(object):
def __init__(self):
self.child = Child()
if __name__ == '__main__':
p = Parent()
assert(id(p) == id(p.child.parent))
Sure that'll work, but just never try to refactor it into a seperate method, or create a base class from it.
you could* try to use the traceback module, just to prove a point.
**Don't try this at home, kids*
This can be done in python with metaclasses.

Categories