Write attribute to scope above current one - python

I am wondering if there is a way to programatically write an attribute to the class of a parent in which a function is run. I am looking for something like the following.
def add_items():
setattr(ParentClass, 'foo', 'bar')
class A(object):
add_items()
class B(object):
add_items()
a = A()
b = B()
print a.foo
"bar"
print b.foo
"bar"

It is not clear to me what you are after. Here are two attempts to answer your question.
You can make a decorator which adds attributes to a class:
def add_items(cls):
cls.foo = "bar"
return cls
#add_items
class A(object):
pass
On the other hand, if your function is a method, it can add whatever attributes it wants to the class instance:
class B(object):
def add_items(self):
self.foo = 'Baz'
b = B()
b.add_items()

Related

Replace method with method of instance of different class

I just tried to make a system with some classes with similar parent class, which dynamically assigns their method between them, It looks like one function "transform(from, to)", which doing smth like from.foo = to.foo
So, you see, that my problem is difficult with Python, so I'm asking for help
My first try was
def transform(a, b):
a.foo = b.foo
class A:
def foo(self):
pass
class B(A):
def foo(self):
print("bar")
transform(self, C())
class C(A):
def foo(self):
print("foo")
transform(self, B())
b = C()
b.foo()
b.foo()
b.foo()
b.foo()
I want to get from it smth like
foo
bar
foo
bar
But I get
foo
bar
bar
bar
The funniest moment of all is that first conversion working, but next.
My next try was
class A:
def foo(self):
pass
def transform(self, to):
self.foo = to.foo
class B(A):
def foo(self):
print("bar")
self.transform(C())
class C(A):
def foo(self):
print("foo")
self.transform(B())
b = C()
b.foo()
b.foo()
b.foo()
b.foo()
and I got the same result. Do you have any idea how to manage this conversion?
In your code, it first runs a.foo = b.foo, where a was the object created at b = C(), and b was the object created at B(). Then when a.foo() is next run, it runs B's foo(self) where self is that B() object. There, it runs transform(self, C()) where self is still the object created with B(), not the object at b. Basically, b is only modified once then never modified again.
Instead, you should get the unbound function object of foo with b.foo.__func__ before assigning it to the other one, or the self in foo will refer to the object B() instead of b. Then, you can bind it back to the destination object with types.MethodType:
from types import MethodType
def transform(a, b):
a.foo = MethodType(b.foo.__func__, a)
class A:
def foo(self):
pass
class B(A):
def foo(self):
print("bar")
transform(self, C())
class C(A):
def foo(self):
print("foo")
transform(self, B())
b = C()
b.foo()
b.foo()
b.foo()
b.foo()
foo
bar
foo
bar
Your 2nd attempt is also fixed by doing the same thing:
from types import MethodType
class A:
def foo(self):
pass
def transform(self, to):
self.foo = MethodType(to.foo.__func__, self)
class B(A):
def foo(self):
print("bar")
self.transform(C())
class C(A):
def foo(self):
print("foo")
self.transform(B())
b = C()
b.foo()
b.foo()
b.foo()
b.foo()
foo
bar
foo
bar

super() of python2.7 skips direct parents?

When I tried to call the bar() of class B from class C, which is a direct subclass of B, it turned out that the bar() of class A was called. But I explicitly required that the B version should be used. How can the method be resolved to that of A?
class A(object):
def bar(self):
print('bar from A')
class B(A):
def bar(self):
print('bar from B')
class C(B):
def bar(self):
super(B, self).bar()
c = C()
# It should print "bar from B"
c.bar()
# But actually it prints "bar from A"
It's because super(sub_class, instance).method() means call the method method of the parent of sub_class on the instance instance. Since the parent of B is A, the result makes sense.
What you want is super(C, self).bar().

How to change parent attribute in subclass python

I have the following class
class Foo():
data = "abc"
And i subclass it
class Bar(Foo):
data +="def"
I am trying to edit a parent class attribute in subclass. I want my parent class to have some string, and my subclass should add some extra data to that string. How it should be done in Python? Am i wrong by design?
You ask two questions:
How it should be done in Python?
class Bar(Foo):
data = Foo.data + "def"
Am i wrong by design?
I generally don't use class variables in Python. A more typical paradigm is to initialize an instance variable:
>>> class Foo(object):
... data = "abc"
...
>>> class Bar(Foo):
... def __init__(self):
... super(Bar, self).__init__()
... self.data += "def"
...
>>> b = Bar()
>>> b.data
'abcdef'
>>>
You can initialize the state of the Foo class from the Bar class and then append to the data like so:
class Foo(object):
def __init__(self):
self.data = "abc"
class Bar(Foo):
def __init__(self):
super(Bar, self).__init__()
self.data += "def"
When you instantiate an instance of Bar, the value of data that results is:
abcdef
You can refer to class variables of Foo from Bar's namespace via regular attribute access:
class Bar(Foo):
data = Foo.data + 'def'
I don't know if it's a good practice, but there's no reason for it to be bad.

Python subclasses calling parent function

class A():
class B():
def Foo(self):
print "Hello"
class C():
def Bar(self):
print "Goodbye"
def name(self):
print "FooBar"
What I want to do is, within the Bar function is call the Foo function. How would I do that?
In Python, inner classes don't have an implicit instance of the outer class associated with them. Without such an instance, you can't call A's non-static methods from B or C.
If you do have such an instance, then simply use the dot notation:
class C():
def Bar(self):
self.a.name()
...
(where self.a is an instance of A.)
Alternatively, if A.name() can be made static, the following will also work:
class A(object):
class C():
def Bar(self):
print "Goodbye"
A.name()
#staticmethod
def name():
print "FooBar"
A.C().Bar()
You need an instance of class A to call a method.

Accessing outer class methods from an inner class

I want a python class that has a nested class where the inner class can access the members of the outer class. I understand that normal nesting doesn't even require that the outer class has an instance. I have some code that seems to generate the results I desire and I want feedback on style and unforeseen complications
Code:
class A():
def __init__(self,x):
self.x = x
self.B = self.classBdef()
def classBdef(self):
parent = self
class B():
def out(self):
print parent.x
return B
Output:
>>> a = A(5)
>>> b = a.B()
>>> b.out()
5
>>> a.x = 7
>>> b.out()
7
So, A has an inner class B, which can only be created from an instance of A. Then B has access to all the members of A through the parent variable.
This doesn't look very good to me. classBdef is a class factory method. Usually (and seldomly) you would use these to create custom classes e.g. a class with a custom super class:
def class_factory(superclass):
class CustomClass(superclass):
def custom_method(self):
pass
return CustomClass
But your construct doesn't make use of a customization. In fact it puts stuff of A into B and couples them tightly. If B needs to know about some A variable then make a method call with parameters or instantiate a B object with a reference to the A object.
Unless there is a specific reason or problem you need to solve, it would be much easier and clearer to just make a normal factory method giving a B object in A instead of stuff like b = a.B().
class B(object):
def __init__(self, a):
self.a = a
def out(self):
print self.a.x
class A(object):
def __init__(self,x):
self.x = x
def create_b(self):
return B(self)
a = A()
b = a.create_b()
b.out()
I don't think what you're trying to do is a very good idea. "Inner" classes in python have absolutely no special relationship with their "outer" class, if you bother to define one inside of another. It is exactly the same to say:
class A(object):
class B(object):
pass
as it is to say:
class B(object): pass
class A(object): pass
A.B = B
del B
That said, it is possible to accomplish something like what you're describing, by making your "inner" class into a descriptor, by defining __get__() on its metaclass. I recommend against doing this -- it's too complicated and yields little benefit.
class ParentBindingType(type):
def __get__(cls, inst, instcls):
return type(cls.__name__, (cls,), {'parent': inst})
def __repr__(cls):
return "<class '%s.%s' parent=%r>" % (cls.__module__,
cls.__name__, getattr(cls, 'parent', None))
class B(object):
__metaclass__ = ParentBindingType
def out(self):
print self.parent.x
class A(object):
_B = B
def __init__(self,x):
self.x = x
self.B = self._B
a = A(5)
print a.B
b = a.B()
b.out()
a.x = 7
b.out()
printing:
<class '__main__.B' parent=<__main__.A object at 0x85c90>>
5
7

Categories

Resources