Dynamically adding class instance to Python instance à la __setattr__ - python

Suppose I have two Python classes, A and B. I would like to be able to do the following:
>>> b = B()
>>> b.a.attr1 = 'foo'
>>> b.a.attr2 = 'bar'
where 'a' is an instance of A. I can't use __setattr__ as I would if 'a' was some
"primitive" type. Is there some elegant way to accomplish this, other than
>>> b = B()
>>> b.a = A()
>>> b.a.attr1 = 'foo'
>>> b.a.attr2 = 'bar'
?

You'd have to either create a in the __init__ of B, use a __getattr__ hook to create a dynamically, or use a property.
__init__ approach:
class B(object):
def __init__(self):
self.a = A()
__getattr__ approach:
class B(object):
def __getattr__(self, attr):
if attr == 'a':
self.a = A()
return self.a
raise AttributeError(attr)
Property approach:
class B(object):
_a = None
#property
def a(self):
if self._a is None:
self._a = A()
return self._a
Of course, the property and __getattr__ approaches do not have to store the A() instance on self, it could just return a pre-existing A() instance from somewhere else instead.

class A(object):
pass
class B(object):
def __init__(self):
self.a = A()
b = B()
b.a.attr1 = 'foo'
b.a.attr2 = 'bar'

Related

Taking Python class method as a polymorphic function

Edit: this question is based on two mistakes: not originally yincluding self in methods and assuming unbounded methods would not exhibit polymorphism, but they do. I voted to close it.
I can take a method as a function-valued object in Python:
class A:
def foo(self):
return "Hi, I'm A.foo"
f = A.foo
a = A()
print(f(a))
produces Hi, I'm A.foo.
So far so good. However, f won't work for sub-classes:
class B(A):
def foo(self):
return "Hi, I'm B.foo"
f = A.foo
b = B()
f(b)
still produces Hi, I'm A.foo, whereas b.foo() produces Hi, I'm B.foo. In other words, polymorphism does not apply.
Question: is there a way to get a function-valued object in f so that f(x) == x.foo() whenever isinstance(x, A)?
In other words, how do I complete the snippet below for things to work?
class A:
def foo(self):
return "Hi, I'm A.foo"
class B(A):
def foo(self):
return "Hi, I'm B.foo"
f = <WHAT DO I PUT HERE?>
a = A()
b = B()
assert f(a) == a.foo()
assert f(b) == b.foo()
Your can pull the class name out like so:
class A:
def foo(self):
return "Hi, I'm {}.foo".format(self.__class__.__name__)
class B(A):
def foo(self):
return "Hi, I'm {}.foo".format(self.__class__.__name__)
f = A.foo # this could be A or B, doesn't matter
a = A()
b = B()
assert f(a) == a.foo()
assert f(b) == b.foo()
Note that because B inherits from A, you don't even need the foo method there:
class A:
def foo(self):
return "Hi, I'm {}.foo".format(self.__class__.__name__)
class B(A):
pass
f = A.foo
a = A()
b = B()
assert f(a) == a.foo()
assert f(b) == b.foo()

Python return instance of a different class from class instead of self

I am going to try my best to explain what I am trying to accomplish. I am trying to return an instance of a new class from a class instead of return self. Please refer to the comments in the example code.
class Test(object):
def __init__(self, a):
self.a = a
def methoda(self):
return len(self.a)
class SomeClass(object):
def __init__(self, lol):
self.lol = lol
self.test = Test(self.lol)
def __call__(self):
return self.test # this isnt going to work
c = SomeClass('bar')
print(c) # trying to access the Test class attributes and methods here
# so in the above example, i want to do
# print(c.a) # print bar
# print(c.length() # print 3
__repr__ and __str__ wouldnt work in this case because I am trying to get the Test class object back.
Other things i have tried in SomeClass is having something like self.test = Test(self.lol), but that doesnt seem to quite do what I want.
How can I do this?
You can override the __getattr__ method of SomeClass so that attributes not defined in a SomeClass object can be delegated to self.test:
class Test(object):
def __init__(self, a):
self.a = a
def methoda(self):
return len(self.a)
class SomeClass(object):
def __init__(self, lol):
self.lol = lol
self.test = Test(self.lol)
def __getattr__(self, item):
return getattr(self.test, item)
c = SomeClass('bar')
print(c.methoda())
This outputs:
3
No quite convinced of the use case but you can use some proxy methods in SomeClass (use property whenever needed) to delegate the calls to the respective Test methods:
In [343]: class Test(object):
...: def __init__(self, a):
...: self.a = a
...:
...: def methoda(self):
...: return len(self.a)
...:
...:
...: class SomeClass(object):
...: def __init__(self, lol):
...: self.lol = lol
...: self.test = Test(self.lol)
...:
...: #property
...: def a(self):
...: return self.test.a
...:
...: def length(self):
...: return self.test.methoda()
...:
...: def __call__(self):
...: return self.test
...:
In [344]: c = SomeClass('bar')
In [345]: c.a
Out[345]: 'bar'
In [346]: c.length()
Out[346]: 3
Also note that, you can call the SomeClass instance i.e. c as you have the __call_- method defined, and returns the Test instance. That way you can get the values using:
In [347]: print(c())
<__main__.Test object at 0x7fba862fc3c8>
In [348]: print(c().a)
bar
In [349]: print(c().methoda())
3
For this you need to understand when __init__ is called and when __call__ is called.
class foo(object):
def __init__(self, lol):
print('__init__ called')
def __call__(self):
print('__call__ called')
ob = foo('lol')
print(ob())
_ = foo('lol')()
this will output:
__init__ called # ob = foo('lol')
__call__ called # print(ob())
__init__ called # _ = foo('lol')()
__call__ called # _ = foo('lol')()
__init__ is called when class is instantiate. __call__ is called when you call that object of class as function.
To access Test class in your case you can do following.
c = SomeClass('bar')
test_c = c()
print(c.a)
print(c.methoda)
What you are looking for is the __new__ special method. It allows to build from scratch the object created from the class:
class SomeClass(object):
def __new__(cls, lol):
obj = Test(lol)
return obj
You can then use it:
>>> c = SomeClass('bar')
>>> c
<__main__.Test object at 0x03F87750>
>>> c.a
'bar'
>>> c.methoda()
3
But you should not unless you make Test a subclass of SomeClass. It is at least uncommon that SomeClass('bar') returns an object that is not a SomeClass, and you could be burned later because of that...

How can I make a class which has a public method that cannot be inherited by its sub-class?

I want to make a class A like this
class A:
#someDecorator
def f(self):
print('A.f')
def g(self):
print('A.g')
And I can use it like this
a = A()
a.f() #prints A.f
a.g() #prints A.g
But if I declare a class B as a subclass of A, attribute f of class B will become invisible
class B(A):
pass
b = B()
b.g() #prints A.g
b.f() #error: no such attribute
How can I make this #someDecorator?
One way is to check __class__ of the method, and return if it matches A.
def disable_method(func):
def func_wrapper(name):
if name.__class__ == A:
return func(name)
else:
raise AttributeError("Cannot call inherited method")
return func_wrapper
class A:
#disable_method
def f(self):
print('A.f')
def g(self):
print('A.g')
class B(A):
pass
a = A()
a.f()
#A.f
b = B()
b.f()
#AttributeError: Cannot call inherited method
Edit: Looking at this again it is possible to check whether the method's class has a superclass by __bases__. It should work as long as its being used as a decorator.
def disable_method(func):
def func_wrapper(name):
if name.__class__.__bases__ == object:
return func(name)
else:
raise AttributeError("Cannot call method from superclass")
return func_wrapper

How to make python function always unbound even assigned to a class attribute

Having the following code, what can I do with the 'foo' function to make it unbound in any case even if it is assigned to class attribute? Overriding __get__ doesn't help - as far as I understand because it is not used when function is absent from __dict__ of an instance (it is so in case of class attributes).
But what else can be done here?
def foo(x):
print(x)
def foo_get(self, obj, type=None):
return foo
foo.__get__ = foo_get
class A(object):
def __init__(self):
self.f = foo
class B(object):
f = foo
a = A()
print(a.f) #<function foo at 0x2321d10>
print(a.f.__get__(a, A)) #<function foo at 0x2321d10>
b = B()
print(b.f) #<bound method B.foo of <__main__.B object at 0x23224d0>>
I'm pretty sure you want #staticmethod.
foo = staticmethod(foo)
You can also define __get__ on a callable class:
class Foo(object):
def __get__(self, obj, type=None):
return self
def __call__(self, x):
print(x)
foo = Foo()
class A(object):
def __init__(self):
self.f = foo
class B(object):
f = foo
foo(1) # 1
a = A()
a.f(1) # 1
print(a.f) #<function foo at 0x2321d10>
print(a.f.__get__(a, A)) #<function foo at 0x2321d10>
b = B()
b.f(1) # 1
print(b.f) #<__main__.Foo object at 0x7fa8c260be10>
It's one extra level of indentation and a few extra lines of code, but that's how it can be done, if it's important.

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