python the difference between class(dict) and class(str) - python

I am wondering what kind of difference exists between class(dict) and class(str)
Here is my code
class MyDict3(str):
def __init__(self):
self.a = None
class MyDict(dict):
def __init__(self):
self.a = None
These classes are what I made for clarification
and then I type below
>>> mydict['a'] = 1
>>> mydict
{'a': 1}
>>> mydict3['a'] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyDict3' object does not support item assignment
Why does my mydict3['a'] make an error?
The difference that I made is only MyDict(dict) and MyDict(str)
As far as I know, the object that I specified(dict, str) is just nothing but constructer like c++,java
Please give me a clear answer on that.

Why does my mydict3['a'] make an error? The difference that I made is only MyDict(dict) and MyDict(str) As far as I know, the object that I specified(dict, str) is just nothing but constructer like c++,java
I believe that you're doing a confusion here, thinking that a class attribute and an item are the same thing, like the following javascript code:
> foo = {'a': 42};
{ a: 42 }
> foo.a
42
> foo['a']
42
> foo.a === foo['a']
true
But in python foo.a and foo['a'] are two different mechanisms. When you call foo.a you're actually accessing the a attribute of a class, which is defined through the class definition:
class Foo:
def __init__(self):
self.a = 42 # declaring and defining the a attribute
so then you can access it using:
>>> foo = Foo()
>>> print(foo.a)
42
But to have foo['a'] working, you have to use the indexing mechanism, which is usually used for dicts or lists:
>>> foo = {'a': 42}
>>> foo['a']
42
That mechanism is being implemented by the __getitem__ method of your class, so you can overload it if you want:
class Foo:
def __getitem__(self, val):
if val == 'a':
return 42
raise KeyError('Unknown key') # when the key is unknown, you raise a key error exception
>>> foo = Foo()
>>> foo['a']
42
>>> foo['b']
KeyError: 'Unknown key'
So, the dict class is a class that implements __getitem__ (and __setitem__ and many others), in order to provide you a proper mapping mechanism called a dictionary. There keys can be any immutable objects, and values anything. For a list, it shall be only integers (which are the positions in the list).
That being said, let's answer your question:
Why does my mydict3['a'] make an error?
obviously it's because you defined mydict3 as being an implementation of a string, which has a special implementation for the __getitem__ method: it's giving you a character at the parameter position like if the list was a list of character (like in C).
So when you're trying to index mydict3 with 'a', python just tells you that what you're asking makes no sense!
So in the end, when you say:
The difference that I made is only MyDict(dict) and MyDict(str)
it's actually a very big difference! A dict and an str do not have the same interface, and thus what you want to do cannot work!
P.S.: Actually, nothing is black or white. The implementation of a class actually is a dict, and you can access all members of a class' instance through the __dict__ member of an instance:
class Foo():
def __init__(self):
self.a = 42
>>> foo = Foo()
>>> foo.__dict__['a']
42
but you shall never directly access the __dict__ instance directly, and use helper functions setattr and getattr:
>>> setattr(foo, 'b', 42)
>>> getattr(foo, 'b')
42
>>> getattr(foo, 'a')
42
This is some advanced python tricks, and they should be use with care. If there's really no other way to do it, then maybe you should use that.
Also, there exists a special class that transform dict items as class members, it's the namedtuple:
>>> from collections import namedtuple
>>> d = {'a': 42, 'b': 69}
>>> SpecialDict = namedtuple('SpecialDict', d.keys())
>>> foo = SpecialDict(**d)
>>> d.a
42
>>> d.b
69
HTH

Related

How to get the id of the underlying function bound to an object by a method-wrapper?

Consider the following case:
>>> "a".capitalize.__call__
<method-wrapper '__call__' of builtin_function_or_method object at 0x1022e70d8>
>>> "a".capitalize.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x1022e2b70>
>>> id("a".capitalize.__call__)
4331547448
>>> id("a".capitalize.__call__.__call__)
4331547504
>>> id("a".capitalize.__call__) == id("a".capitalize.__call__.__call__)
False
How can I establish at runtime that the __call__ refers to the same base symbol in both cases ?
Edit:
It is possible that expecting something like this to exist for __call__ in the first place is unreasonable because __call__ might not have a base symbol that is not bound to any object - in which case what is the best way to detect that other than keeping a list of special names (how can such a list be built authoritatively ?) ?
Won't work for builtin_function_or_method as they have no __func__.
If you're only working with your classes you can compare __func__:
>>> class Foo:
... def bar(self):
... pass
...
>>>
>>> a = Foo()
>>> b = Foo()
>>> a.bar.__func__
<function Foo.bar at 0x7f6f103e5ae8>
>>> a.bar.__func__ is b.bar.__func__
True
But I'd say it's better to do it the other way around: instead of trying to get the function from the instance, get up to the type first:
type(a).bar is type(a).bar
Which should work even for bltns:
>>> type("").capitalize is type("a").capitalize
True
And for hierarchies:
>>> class A:
... def foo(self):...
...
>>> class B(A):...
...
>>> a = A()
>>> b = B()
>>> type(a).foo is type(b).foo
True

how to understand this example of __getattr__ as metaclass method

Here is a snippet of example from Mark Lutz's book "Learning Python". I found it difficult to understand as to how name accesses are translated into getattr() calls in the metaclass:
>>> class A(type):
def __getattr__(cls, name):
return getattr(cls.data, name)
>>> class B(metaclass=A):
data = 'spam'
>>> B.upper()
'SPAM'
>>> B.upper
<built-in method upper of str object at 0x029E7420>
>>> B.__getattr__
<bound method A.__getattr__ of <class '__main__.B'>>
>>> B.data = [1, 2, 3]
>>> B.append(4)
>>> B.data
[1, 2, 3, 4]
>>> B.__getitem__(0)
1
>>> B[0]
TypeError: 'A' object does not support indexing
I have the following questions:
how does B.upper() yield 'SPAM'? Is it because B.upper() => A.__getattr__(B, upper()) => getattr(B.data, upper())? but a call like getattr('spam', upper()) gives error "NameError: name 'upper' is not defined"
what path does B.upper go to yiled <built-in method upper of str object at 0x029E7420>. does it go through getattr too, what is the true value of the arguments?
Does B.append(4) go through A.__getattr__(cls, name)? if it does, what is the true values of the arguments in getattr(cls.data, name) in this case?
how does B.__getitem__(0) yield 1? what is the true values of the arguments in getattr(cls.data, name) in this case?
B.upper() first looks up B.upper and then calls it with no arguments. B.upper is looked up by trying several options in a certain order, eventually trying type(B).__getattr__(B, 'upper'), which in this case is A.__getattr__(B, 'upper'), which returns 'spam'.upper.
As mentioned above, B.upper goes through several options, in this case reaching type(B).__getattr__(B, 'upper') which is A.__getattr__(B, 'upper').
Yes, in this case, B.append will reach A.__getattr__(B, 'append') which will return B.data.append.
B.__getitem__(0) will in this case look up B.__getitem__ and find it via A.__getattr__(B, '__getitem__') which will return B.data.__getitem__.
Also, note the final example, B[0], doesn't work because the B class doesn't directly define a __getitem__ method. This is because "special" methods, such as __getitem__, are looked up differently when used via their special syntax, such as B[0] in this case.
First you don't need to add the usual confusion of a meta class to get this behaviour, you can just as easily use a regular class and an instance to use as an example:
class A():
def __getattr__(cls, name):
return getattr(cls.data, name)
B = A()
B.data = "spam"
>>> B.data
'spam'
>>> B.upper
<built-in method upper of str object at 0x1057da730>
>>> B.upper()
'SPAM'
>>> B.__getitem__
<method-wrapper '__getitem__' of str object at 0x1057da730>
>>> B.__getitem__(0)
's'
>>> B[0]
Traceback (most recent call last):
File "<pyshell#135>", line 1, in <module>
B[0]
TypeError: 'A' object does not support indexing
Next keep in mind that B[0] does not look up B.__getitem__ using your special method but rather tries to access it directly on type(B) which does not have a __getitem__ so the indexing fails.
how does B.upper() yield 'SPAM'? Is it because B.upper() =>
A.getattr(B, upper()) => getattr(B.data, upper())? but a call
like getattr('spam', upper()) gives error "NameError: name 'upper'
is not defined"
getattr('spam', upper()) does not make any sense, the name of the attribute is always a string, so using B.upper (no calling yet) would be equivelent to getattr(B, "upper") then you call the method.
what path does B.upper go to yiled . does it go through getattr too, what is the
true value of the arguments?
Is there any reason you are not just adding a print statement to check?
class A():
def __getattr__(cls, name):
print("calling __getattr__ for this name: %r"%name)
return getattr(cls.data, name)
>>> B = A()
>>> B.data = "spam"
>>> B.upper
calling __getattr__ for this name: 'upper'
<built-in method upper of str object at 0x1058037a0>
both 3 and 4 are answered by adding this print statement:
>>> B.data = [1,2,3,4]
>>> B.append(5)
calling __getattr__ for this name: 'append'
>>> B.__getitem__(0)
calling __getattr__ for this name: '__getitem__'
1

Why can't I change attribute of a class in Python

We say classes are mutable in Python which means you can using references we can change the values that will be reflected in object. For example,
>>> A = [1, 2, 3]
>>> B = A
>>> B[2] = 5
>>> A
[1, 2, 5]
Here I can change the values of A object using B because list is a mutable type. My question is why can't I change the attributes of a class below using same concept:
class C:
apple = 2
def __init__(self):
self.dangerous = 2
D = C # D is pointing to same class C
D().dangerous = 5 # changing the value of class attribute D
D().apple = 3 # changing the value of apple here
print D().apple
print D().dangerous
OUTPUT:
2
2
Could anyone explain why the output is 2 and 2 but not 3 and 5 since we are saying that the class is a mutable type.
UPDATE : Referring to the answer by #zxq9, if you see the below diagram when do D=C, D is actually pointing to the same class rather a new object as you have described. Could you explain this:
Each time you place parens after a class, you are constructing a new instance object of the class. So the things you printed were brand-spanking new and did not reflect the short-lived assignments you had made previously.
Here is an example (expanded to cover the underlying reference to class C):
>>> class C:
... red = 2
... def __init__(self):
... self.blue = 2
...
>>> C.red
2
>>> C.blue
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'blue'
>>> C().red
2
>>> C().blue
2
>>> #OOOOH!
...
>>> z = C()
>>> z.red
2
>>> z.blue
2
>>> D = C
>>> D.red
2
>>> D().red
2
>>> D().red = "over 9000!"
>>> D.red
2
>>> D.red = "No, really over 9000!"
>>> D.red
'No, really over 9000!'
>>> C.red
'No, really over 9000!'
>>> #OOOOOOHHHH!
...
Note that we did change the class directly when I assigned D.red = "No, really over 9000!" -- because that was referencing the class definition itself, not an instantiated object created from it. Note also that assigning an attribute of D (a copy) changed the attribute of C (the original) because in many (but not all) cases Python makes such assignments by reference, meaning that D is really an alias of C, not copy of the underlying structure. Read up on Python's deepcopy() method for more about that particularly startling detail.
Walk through the example code carefully, note the difference between referencing ClassName and calling ClassName(). The first is a reference via a variable name to a class definition -- a blueprint for generating instance objects that carries a constructor function __init__() with it. The second is an invokation of __init__() whose return value is an instance object of the class within which it is defined.
This is also why you can do things like this:
def some_fun(another_fun, value):
another_fun(value)
def foo(v):
return v + v
def bar(v):
return v * v
some_fun(foo, 5)
some_fun(bar, 5)
This feature lends Python a high degree of flexibility in building functional abstractions. (Now if only it had tail-call elimination...)
It is an interesting example.
The line D().dangerous = 5 will change the attribute "dangerous" of the instance D(); But the line print D().dangerous print out the attribute "dangerous" of ANOTHER instance D().
The line D().apple = 3 will create an attribute "apple" in the instance D() since this instance does not have the attribute "apple".
The line print D().apple will print out the attribute "apple" of the class D since the instance D() does not have the attribute "apple".
One way to change the attribute "apple" of the class through its instance is by using D().__class__.apple=3

Python, how to deal with A(a) when type(a) is yet A

I need to create a class that mimics this behavior (in mathematics, we say list, dict, are "idempotent"):
>>> list(list([3,4]))
[3, 4]
>>> dict({'a':1,'b':2})
{'a':1,'b':2}
So, if A is my class, I want to write
>>> a = A(1)
>>> b = A(a)
>>> b == a
True
I imagine my class A has to look like this :
class A(object):
def __init__(self,x):
if isinstance(x, A) :
self = x
else :
self.x = x
self.y = 'hello'
I try it
>>> A(1).x
1
>>> A(A(1)).x
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
It does not work !
I don't want to copy x attributes in self, i just want self to BE x or "point" x
Some idea ?
Thanks
What you are looking for is the __new__() method, which takes is run before the class is constructed, as opposed to __init__(), which takes place after. With __new__() you can hook in and replace the object being created.
def __new__(cls, x):
if isinstance(x, A):
return x
else:
return object.__new__(cls, x)
You can't do this in __init__() as the object has already been created. Changing self simply changes the value of the local variable, it doesn't affect the object.
It's also worth noting that type-checking is almost always the wrong thing to do in Python. Instead, check to see if the class has the information/attributes you need. This way, someone can create a class that acts like yours and works with your code.
As a final word of warning, this is pretty confusing behaviour - people won't expect your class to act like this and it's generally not a great idea. Your example of list() and dict() isn't accurate to what you are doing here, as list(some_list) does not give some_list, it gives a new list which is a copy of some_list - the same is true for dict():
>>> x = [1, 2, 3]
>>> list(x) is x
False
When you call a constructor, it's natural to expect a new object, rather than a reference to the existing one. I would recommend making A(some_a) copy some_a, and restructure your calling code not to rely on A(some_a) is some_a).

Yielding a dictionary containing an object's attributes in Python

I'm currently trying to write a piece of code that will dump all attributes of a given class instance to a dictionary so that I can change them without changing the source object. Is there a method for doing this, or perhaps a built-in dictionary I can copy and access?
What I'm really doing is making a special class that copies the actual attributes (and their corresponding values) from instances of varying other classes. Basically it would mimic any instance of any class.
For example, object x has attributes x.name and x.number, "Joe" and 7, respectively. I want my new object mimic, object y, to copy the attributes so that y now has attributes y.name and y.number, "Joe" and 7.
Thanks!
EDIT: I found what I was looking for shortly after posting this!
Python dictionary from an object's fields
That's pretty much all I needed to know.
Why not write a __getattr__() (or __getattribute__()) method on your "mimic" object that does this only when an attribute is requested, rather than copying the attributes? Among other benefits, this will keep properties as executable code (rather than copying their return value) and will work even if a new attribute is added to the mimicked object after you create the mimic object. (Also, I would call it a wrapper or proxy object rather than a mimic.) Something like:
class Wrapper(object):
def __init__(self, obj):
self.__wrapped__ = obj
def __getattr__(self, key):
return getattr(self.__wrapped__, key)
l = [3, 2, 1]
w = Wrapper(l)
print w.index(2) # calls through to l.index()
Very object has a __dict__ attribute that maps names (variables) to the values they are bound to. Muck around with that.
>>> class MyObj(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> foo = MyObj('Joe', 7)
>>> foo.x
'Joe'
>>> foo.y
7
>>> foo.__dict__
{'y': 7, 'x': 'Joe'}
>>> class Mimic(object):
... def __init__(self, obj):
... self.__dict__.update(obj.__dict__)
...
>>> m = Mimic(foo)
>>> m.x
'Joe'
>>> m.y
7
>>> print m.__dict__
{'y': 7, 'x': 'Joe'}
>>>

Categories