I have two classes, B and C.
I want to instantiate B with C reference and C with B reference.
I could add a setter method, but was wondering if I can do it in the __init__ stage or any other elegant ways
It is not possible within __init__ directly due to a chicken and egg situation. However, it is possible in one assignment statement:
>>> class A:
... pass
...
>>> class B:
... pass
...
>>> a, b = b.a, a.b = A(), B()
>>> a.b is b
True
>>> b.a is a
True
This relies on the fact that Python evaluates assignments left to right.
It is not thread safe; if you need to guarantee that the references exist in a threaded application then you'll want to use a mutex to handle the possible race conditions. The GIL works at the opcode level, which is a finer-grained resolution than lines of Python code.
You could do it in __init__ if you make one of the class initializers take an object of the other class:
>>> class B:
... def __init__(self):
... self.c = C(self)
...
>>> class C:
... def __init__(self, b):
... self.b = b
...
>>> b = B()
>>> c = b.c
>>> b.c
<__main__.C object at 0x107a4f6d8>
>>> b.c.b.c
<__main__.C object at 0x107a4f6d8>
>>> b.c.b.c.b
<__main__.B object at 0x107a60e80>
>>> b
<__main__.B object at 0x107a60e80>
>>> c
<__main__.C object at 0x107a4f6d8>
>>> c.b
<__main__.B object at 0x107a60e80>
>>> b.c
<__main__.C object at 0x107a4f6d8>
>>> b.c.b.c
<__main__.C object at 0x107a4f6d8>
>>> c.b.c.b
<__main__.B object at 0x107a60e80>
Or even without any arguments to __init__:
>>> class B:
... def __init__(self):
... self.c = C()
... self.c.b = self
...
>>> class C:
... pass
...
>>> b = B()
>>> c = b.c
>>> b
<__main__.B object at 0x10835c048>
>>> c
<__main__.C object at 0x1085ccac8>
>>> b.c
<__main__.C object at 0x1085ccac8>
>>> c.b
<__main__.B object at 0x10835c048>
>>> b.c.b.c.b
<__main__.B object at 0x10835c048>
Related
Consider the following example:
class A:
def m():
pass
class B(A):
pass
And the following terminal output:
>>> b = B()
>>> b.m
<bound method A.m of <__main__.B object at 0x000001EFFF24C748>>
>>> super(b.__class__, b).m
<bound method A.m of <__main__.B object at 0x000001EFFF24C748>>
>>> b.m is super(b.__class__, b).m
False
>>> b.m == super(b.__class__, b).m
True
Why are they equal but not identical? Is a copy of the method made when it is inherited?
Are there better ways to test whether a child class has overridden a parent method?
You can use the __dict__ attribute to check which methods and attributes have been overridden:
>>> class A:
... def m():
... pass
...
>>> class B(A):
... pass
...
>>> class C(A):
... def m():
... pass
...
>>> 'm' in A.__dict__
True
>>> 'm' in B.__dict__
False # not overridden
>>> 'm' in C.__dict__
True # overridden
Using super(b.__class__, b) produces an object that implements a __getattr__ method that will go up the __mro__ attribute starting at position 1 (skipping the current class) and look for the first class that has the specified attribute. It will then return that bound method. For a better explanation see this answer.
Knowing that all functions are also descriptors the following
class A:
def m(self):
pass
creates an object A with the attribute m which will be a function and descriptor. When you initialize an object a of class A, it will basically result in a.m = A.m.__get__(a) which produces the bound method that has a as the first argument self.
Now since super also retrieves bound methods what is being checked is the identity between 2 instances of A.m.__get__(a) producing your terminal output:
>>> A.m.__get__(a)
<bound method A.m of <__main__.A object at 0x...>>
>>> A.m.__get__(a) is A.m.__get__(a)
False
So 2 calls to the class descriptor m produce different bound instances and it is why the identity check fails. Instead you should test the identity of the functions that produced the bound methods. Luckily a bound method contains the __func__ attribute that returns the original function. So to lookup whether any instance's class has overridden an inherited function without knowing more than just the instance and name of the function you can do:
>>> a.__class__.m is super(a.__class__, a).m.__func__
True
What I am trying to do is simple, I have a huge dict like so:
class a():
m=0
def __init__(self, m):
self.m = m
def __int__(self):
return self.m
b=a(4)
c=a(6523)
d=a(741)
e=a(84521111)
dict={0:b,1:c,2:e,3:d,4:None,5:None,6:None}
for ele in dict.values():
if ele is not None:
print int(ele)
else:
print "None"
The real one has 4096 elements. Basically, when I decided to kill the object c, I do:
dict[1]=None
Because I don't want to remove the key number 1, and it is working fine, but the object if still alive somewhere and with 4096 objects it can be a problem on my small embedded system. I can check the alive objects with:
import gc
for obj in gc.get_objects():
if isinstance(obj, a):
print obj
Output:
<main.a instance at 0xb749c96c>
<main.a instance at 0xb749caac>
<main.a instance at 0xb749c9cc>
<main.a instance at 0xb749cc0c>
So, how can I delete these object definitely from my memory ?
Nota: del dict[1] doesn't work because it is removed the key as well, same for pop().
I am using Python 2.7, still ...
Ensure you're accounting for the fact that they were in memory before you added them to the dictionary.
>>> b=a(4)
>>> c=a(6523)
>>> d=a(741)
>>> e=a(84521111)
>>>
>>> dict={0:b,1:c,2:e,3:d,4:None,5:None,6:None}
>>>
>>> for obj in gc.get_objects():
... if isinstance(obj, a):
... print obj
...
<__main__.a instance at 0x7f4078a34dd0>
<__main__.a instance at 0x7f4078a34d88>
<__main__.a instance at 0x7f4078a34d40>
<__main__.a instance at 0x7f4078a34cf8>
Now delete the originals:
>>> del(b)
>>> del(c)
>>> del(d)
>>> del(e)
>>>
>>> for obj in gc.get_objects():
... if isinstance(obj, a):
... print obj
...
<__main__.a instance at 0x7f4078a34dd0>
<__main__.a instance at 0x7f4078a34d88>
<__main__.a instance at 0x7f4078a34d40>
<__main__.a instance at 0x7f4078a34cf8>
They're still in memory because they're in the dictionary. Now remove them from the dictionary:
>>> dict[3] = None
>>> dict[2] = None
>>>
>>> for obj in gc.get_objects():
... if isinstance(obj, a):
... print obj
...
<__main__.a instance at 0x7f4078a34dd0>
<__main__.a instance at 0x7f4078a34d88>
>>>
We just lost 2 objects with our delete.
In the below example, the superclass has a __dict__ attribute, while the subclass does not have it.
>>> class Super(object):
... def hello(self):
... self.data1="hello"
...
>>>
>>> class Sub(Super):
... def hola(self):
... self.data2="hola"
...
>>>
>>> Super.__dict__
<dictproxy object at 0x108794868>
>>> Super.__dict__.keys()
['__dict__', '__module__', '__weakref__', 'hello', '__doc__'] # note __dict__
>>> Sub.__dict__.keys()
['__module__', '__doc__', 'hola'] #__dict__ absent here
>>> Sub.__dict__
<dictproxy object at 0x108794868>
Q1: The comments on the above shows where dict is present. why the superclass has it but not the sublcass.
while trying to find out the answer for this, I came across this post. and this confused me further.
>>> class Foo(object):
... __slots__ = ('bar',)
... bar="spam"
...
>>> f = Foo()
>>> f.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__dict__'
>>> class A(object):
... pass
...
>>> b = A()
>>> b.__dict__
{}
Q2: why the instance of Foo throws AttributeError but that of A has empty dict.
Class with slots hasn't dict. Here there is conflict between 'bar' and slots. Delete 'bar' and it will work fine.
I write a python file like :
class A(object):
def update(self, str):
pass
def say(self, str):
print "I update: " + str
def fun(obj, str):
obj.say(str)
a = A()
import types
setattr(A, "update", types.MethodType(fun, None, A))
a.update("hello")
b = A()
b.update("world?")
It change behave of class, the object b have been changed. but, I want to only change object a.
How to change Method of Object in python?
Here is a way to do it:
a.update = lambda x: fun(a, x)
You are setting the class method, while you want to set only the method bound to some instance.
>>> class MyClass(object):
... def a(self): pass
...
>>> MyClass.a = lambda x: x
>>> MyClass.a
<unbound method MyClass.<lambda>>
>>> a = MyClass()
>>> a.a
<bound method MyClass.<lambda> of <__main__.MyClass object at 0x1d7fed0>>
Changing the a method at class level changes also the a methods of all instances.
>>> class MyClass(object):
... def a(self): pass
...
>>> b = MyClass()
>>> b.a = lambda x: x
>>> MyClass.a
<unbound method MyClass.a>
>>> b.a
<function <lambda> at 0x1d88938>
>>> c = MyClass()
>>> c.a
<bound method MyClass.a of <__main__.MyClass object at 0x1d8d110>>
Changing the a method of an instance does not change the method of the class or other instances.
class Foo:
pass
>>> f = test.Foo()
Lets look into the class instance ...
>>> dir(f)
['__add__', [__class__] ...]
Oooh! Lets look into the class instance metadata ...
>>> dir(f.__class__)
['__add__', [__class__] ...]
hmm ... was expecting attributes of __class__ ; but returns back attributes of f
Trying a hit and trial ...
>>> dir(f.__class__.__class__)
['__abstractmethods__', '__base__' ...]
hmm ... why twice a charm?
dir(f) and dir(f.__class__) are showing the attributes of two different things. It's just that your empty object has the same attributes as its own class. Try this:
>>> class Foo:
... def __init__(self):
... self.a = 17
...
>>> f = Foo()
>>> 'a' in dir(f)
True
>>> 'a' in dir(f.__class__)
False