Delete object save in a dict definitely but keep the key - python

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.

Related

Why is an object not created when a method is called during the object's contruction?

Given the class test, why it is not possible to instantiate it by calling one of its methods along with the constructor?
class test:
def __init__(self, a):
self.a = a
def print_a(self):
print(self.a)
Here is an example:
>>> obj = test("Hello").print_a() # Prints the desired output.
Hello
>>> obj
>>> print(obj) # But the object does not exist.
None
>>> obj = test("Hello") # It obviously works when doing it separately.
>>> obj
<__main__.test object at 0x7f537fea3940>
>>> obj.print_a()
Hello
Why is it not possible to chain a method call with the constructor call?
This was implemented in python3.
You are assigning obj to the return value of the function print_a (which is None as it has no return). The actual test object was never stored and is therefore no longer in scope when you try to print it.

instantiating two classes with references to each other

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>

Issue using deepcopy with dictionary inside object

Reading the documentation, I understood that copy.deepcopy(obj) copies recursively any other object inside this one, but when I run:
>>> import copy
>>> class SomeObject:
... a=1
... b={1:1,2:2}
...
>>> o1=SomeObject()
>>> o2=copy.deepcopy(o1)
>>> id(o1)
140041523635624
>>> id(o2)
140041523635912
>>> id(o1.b)
30087968
>>> id(o2.b)
30087968
It does not seem to be copying the dictionary inside 'o1'. Can anyone tell me if I am doing something wrong, or how can I get a copy of the dictionary inside the object?
Thanks
Deepcopy only copies instance attributes. Your b attribute is a class attribute, instead.
Even if you did not create a copy but a new instance of SomeObject manually, b would still be shared:
>>> class SomeObject:
... a=1
... b={1:1,2:2}
...
>>> so1 = SomeObject()
>>> so2 = SomeObject()
>>> so1.b is so2.b
True
>>> so1.b is SomeObject.b
True
Make b an instance attribute:
>>> import copy
>>> class SomeObject:
... a = 1
... def __init__(self):
... self.b = {1: 1, 2: 2}
...
>>> so1 = SomeObject()
>>> so2 = copy.deepcopy(so1)
>>> so1.b is so2.b
False

How to change Method of Object in python

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.

How do I assign a property to an instance in Python?

Using python, one can set an attribute of a instance via either of the two methods below:
>>> class Foo(object):
pass
>>> a = Foo()
>>> a.x = 1
>>> a.x
1
>>> setattr(a, 'b', 2)
>>> a.b
2
One can also assign properties via the property decorator.
>>> class Bar(object):
#property
def x(self):
return 0
>>> a = Bar()
>>> a.x
0
My question is, how can I assign a property to an instance?
My intuition was to try something like this...
>>> class Doo(object):
pass
>>> a = Doo()
>>> def k():
return 0
>>> a.m = property(k)
>>> a.m
<property object at 0x0380F540>
... but, I get this weird property object. Similar experimentation yielded similar results. My guess is that properties are more closely related to classes than instances in some respect, but I don't know the inner workings well enough to understand what's going on here.
It is possible to dynamically add properties to a class after it's already created:
class Bar(object):
def x(self):
return 0
setattr(Bar, 'x', property(Bar.x))
print Bar.x
# <property object at 0x04D37270>
print Bar().x
# 0
However, you can't set a property on an instance, only on a class. You can use an instance to do it:
class Bar(object):
def x(self):
return 0
bar = Bar()
setattr(bar.__class__, 'x', property(bar.__class__.x))
print Bar.x
# <property object at 0x04D306F0>
print bar.x
# 0
See How to add property to a class dynamically? for more information.
Properties use descriptors which only work on classes and thus
for all instances. But you could use a combination of a descriptor on
a class that would consult a per-instance function.
>>> class Foo(object):
... #property
... def x(self):
... if 'x' in self.__dict__:
... return self.__dict__['x'](self)
...
>>> a = Foo()
>>> def k(self):
... return 0
...
>>> a.__dict__['x'] = k
>>> a.x
0
You can assign the property directly to the class object:
>>> class Foo(object):
pass
>>> a = Foo()
>>> a.__class__
__main__.Foo
>>> setattr(a.__class__, 'm', property(lambda self: 0))
>>> a.m
0
>>> a.m = 24
AttributeError: can't set attribute
Here we have taken #agf's solution and used a lambda function to define the class property.
class A(object):
pass
a = A()
a.__class__.f = property(lambda self: 57)
a.f # 57
The following post provides more context: https://crosscompute.com/n/jAbsB6OIm6oCCJX9PBIbY5FECFKCClyV/_/Assign%20a%20class%20property%20to%20an%20instance

Categories