Issue using deepcopy with dictionary inside object - python

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

Related

Python dictionary types as instance variables

I think I am going mad. I did the following in the repel (python3):
class aClass():
da = {}
>>> a = aClass()
>>> b = aClass()
>>> a.da['T'] = 'Hello'
>>> print(a.da)
{'T': 'Hello'}
>>> print(b.da)
{'T': 'Hello'}
>>>
a and b are two different instances of the same class. I assigned something to a, why is it appearing in b?
I did the same but with a string type, no problem at all.
The following works:
>>> a={}
>>> b={}
>>> print(a)
{}
>>> print(b)
{}
>>> a['x']='x'
>>> print(a)
{'x': 'x'}
>>> print(b)
{}
but, that's exactly the same thing isn't it?
aClass.da is a class attribute, not an instance attribute. a.da and b.da are the same dictionary.
Create the dictionary in an __init__ method instead.
class aClass:
def __init__(self):
self.da = {}
(In Python 2, that should be class aClass(object): instead.)
Result:
>>> a = aClass()
>>> b = aClass()
>>> a.da['T'] = 'Hello'
>>> print(a.da)
{'T': 'Hello'}
>>> print(b.da)
{}

Where are the top-level attributes of a class stored in Python

I would like to understand the following situation:
>>> class Test:
... a = 1
...
>>> x = Test()
>>> x.__dict__
{}
>>> x.a
1
>>> x.__dict__
{}
>>> x.a = 1
>>> x.__dict__
{'a': 1}
Where is the a attribute stored at the beginning and how come it becomes visible in the __dict__ only after assignment?
They are stored on the class itself:
>>> class Test:
... a = 1
...
>>> Test.__dict__
{'a': 1, '__module__': '__main__', '__doc__': None}
Python looks first at the instance attributes, then to the class.

Usefulness of def __init__(self)?

I am fairly new to python, and noticed these posts:
Python __init__ and self what do they do? and
Python Classes without using def __init__(self)
After playing around with it, however, I noticed that these two classes give apparently equivalent results-
class A(object):
def __init__(self):
self.x = 'Hello'
def method_a(self, foo):
print self.x + ' ' + foo
(from this question)
and
class B(object):
x = 'Hello'
def method_b(self,foo):
print self.x + ' ' + foo
Is there any real difference between these two? Or, more generally, does __init__ change anything inherently about the attributes of a class? In the documentation it is mentioned that __init__ is called when the instance is created. Does this mean that x in class B is established before instantiation?
Yeah, check this out:
class A(object):
def __init__(self):
self.lst = []
class B(object):
lst = []
and now try:
>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True
and this:
>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False
Does this mean that x in class B is established before instantiation?
Yes, it's a class attribute (it is shared between instances). While in class A it's an instance attribute. It just happens that strings are immutable, thus there is no real difference in your scenario (except that class B uses less memory, because it defines only one string for all instances). But there is a huge one in my example.
In the first exemple you have the variable of the instance of the class. This variable is only accessible through an instance (self required).
class A():
def __init__(self):
self.x = 'hello'
print A.x -> AttributeError
print A().x -> 'hello'
In the second exemple you have a static variable. You can access to this variable thanks to the name of the class A
class A():
x = 'hello'
print A.x -> 'hello'
print A().x -> 'hello'
In fact you can have a static variable and an instance variable with the same name:
class A():
x = 'hello'
def __init__(self):
self.x = 'world'
print A.x -> hello
print A().x -> world
The static value is shared between all the instances
class A():
x = 'hello'
#staticmethod
def talk():
print A.x
a = A()
print a.talk() -> hello
A.x = 'world'
print a.talk() -> world
You have a good article here:
http://linuxwell.com/2011/07/21/static-variables-and-methods-in-python/
As others have stated, it's the difference between a variable on a class and a variable on a class instance. See the following example.
>>> class A:
... a = []
...
>>> class B:
... def __init__(self):
... self.b = []
...
>>> a1 = A()
>>> a1.a.append('hello')
>>> a2 = A()
>>> a2.a
['hello']
>>> b1 = B()
>>> b1.b.append('goodbye')
>>> b2 = B()
>>> b2.b
[]
For immutable objects like tuples, strings, etc. it's harder to notice the difference, but for mutables, it changes everything—the changes applied are shared between ALL instances of that class.
Note also that the same behavior happens for keyword argument defaults!
>>> class A:
... def __init__(self, a=[]):
... a.append('hello')
... print(a)
...
>>> A()
['hello']
>>> A()
['hello', 'hello']
>>> A()
['hello', 'hello', 'hello']
>>> class B:
... def __init__(self, b=None):
... if b is None:
... b = []
... b.append('goodbye')
... print(b)
...
>>> B()
['goodbye']
>>> B()
['goodbye']
>>> B()
['goodbye']
This behavior bites a lot of new Python programmers. Good for you in discovering these distinctions early on!

dir() a __class__ attribute?

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

Getting the class name of an instance

How do I find out the name of the class used to create an instance of an object in Python?
I'm not sure if I should use the inspect module or parse the __class__ attribute.
Have you tried the __name__ attribute of the class? ie type(x).__name__ will give you the name of the class, which I think is what you want.
>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'
If you're still using Python 2, note that the above method works with new-style classes only (in Python 3+ all classes are "new-style" classes). Your code might use some old-style classes. The following works for both:
x.__class__.__name__
Do you want the name of the class as a string?
instance.__class__.__name__
type() ?
>>> class A:
... def whoami(self):
... print(type(self).__name__)
...
>>>
>>> class B(A):
... pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
class A:
pass
a = A()
str(a.__class__)
The sample code above (when input in the interactive interpreter) will produce '__main__.A' as opposed to 'A' which is produced if the __name__ attribute is invoked. By simply passing the result of A.__class__ to the str constructor the parsing is handled for you. However, you could also use the following code if you want something more explicit.
"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)
This behavior can be preferable if you have classes with the same name defined in separate modules.
The sample code provided above was tested in Python 2.7.5.
In Python 2,
type(instance).__name__ != instance.__class__.__name__
# if class A is defined like
class A():
...
type(instance) == instance.__class__
# if class A is defined like
class A(object):
...
Example:
>>> class aclass(object):
... pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>
>>> class bclass():
... pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>
Alternatively you can use the classmethod decorator:
class A:
#classmethod
def get_classname(cls):
return cls.__name__
def use_classname(self):
return self.get_classname()
Usage:
>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Good question.
Here's a simple example based on GHZ's which might help someone:
>>> class person(object):
def init(self,name):
self.name=name
def info(self)
print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person
Apart from grabbing the special __name__ attribute, you might find yourself in need of the qualified name for a given class/function. This is done by grabbing the types __qualname__.
In most cases, these will be exactly the same, but, when dealing with nested classes/methods these differ in the output you get. For example:
class Spam:
def meth(self):
pass
class Bar:
pass
>>> s = Spam()
>>> type(s).__name__
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__ # type not needed here
'Bar'
>>> type(s).Bar.__qualname__ # type not needed here
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'
Since introspection is what you're after, this is always you might want to consider.
You can simply use __qualname__ which stands for qualified name of a function or class
Example:
>>> class C:
... class D:
... def meth(self):
... pass
...
>>> C.__qualname__
'C'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__qualname__
'C.D.meth'
documentation link qualname
To get instance classname:
type(instance).__name__
or
instance.__class__.__name__
both are the same
You can first use type and then str to extract class name from it.
class foo:pass;
bar:foo=foo();
print(str(type(bar))[8:-2][len(str(type(bar).__module__))+1:]);
Result
foo
If you're looking to solve this for a list (or iterable collection) of objects, here's how I would solve:
from operator import attrgetter
# Will use a few data types to show a point
my_list = [1, "2", 3.0, [4], object(), type, None]
# I specifically want to create a generator
my_class_names = list(map(attrgetter("__name__"), map(type, my_list))))
# Result:
['int', 'str', 'float', 'list', 'object', 'type', 'NoneType']
# Alternatively, use a lambda
my_class_names = list(map(lambda x: type(x).__name__, my_list))

Categories