We need more context. Where does this ‘someName’ arise?
someName = "thisname"
print(type(someName))
someName.whatever = "I want!"
print(someName.whatever)
output
<class 'str'>
Traceback (most recent call last):
File "script.py", line 14, in <module>
someName.whatever = "I want!"
AttributeError: 'str' object has no attribute 'whatever'
There you are crossing the line between distinct data types. We cannot assign an attribute to a string object. It’s only attributes are those inherited from its parent class. Python may be loosely typed, but it protects objects a lot more than JavaScript does, to be sure. To both their credit, strings are immutable, so how could we assign them new attributes?
Is there a way to know what Python protects as a type?
Is it possible to protect your own classes in the same way?
Fair about the immutability of strings, but int
is also a class and I also can’t assign to it.
>>> someint = 4
>>> print(type(someint))
<class 'int'>
>>> someint.base = 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'base'
>>> def set_base(b):
return b
>>> int.base = set_base
Traceback (most recent call last):
File "<pyshell#132>", line 1, in <module>
int.base = set_base
TypeError: can't set attributes of built-in/extension type 'int'
>>>
We could say it is possible, but it will take one’s own logic to do it. Python is not a bit player in this exchange.
so what is and what is doing fake_key ???
it was not defined… :S
It is an assigned attribute of the dictionary. This demonstrates that we can give attributes to a class instance without using the __init__()
method in the class definition, or in addition to the initialized instance variables. We’re not confined to just initialized variables. What purpose it will serve one cannot say. It’s mechanics of possibility.
All of the builtins (int, str, boolean, etc) are like this - you can’t assign attributes to them or modify them like that.
This stack overflow post explains that these types are defined in c rather than python, and lack the normal __dict__
property that objects have, which is where attributes are stored:
Here’s a custom class - you can see when I add an attribute, it gets added to the object’s __dict__
"
>>> class TestClass():
... pass
...
>>> tc = TestClass()
>>> tc.__dict__
{}
>>> tc.some_prop = "hello, world!"
>>> tc.some_prop
'hello, world!'
>>> tc.__dict__
{'some_prop': 'hello, world!'}
Whereas a string simply has no attribute __dict__
:
>>> ts = "test string"
>>> ts.some_prop = "this doesnt work"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'some_prop'
>>> ts.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__dict__'
>>>
Also if you try and set a class attribute (rather than an instance attribute) on a builtin, the error message is a bit more helpful:
>>> str.some_class_attr = "test123"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
>>>
if you check someObject.__dict__
and it doesn’t exist - that’s one way to tell!
In exercise 9/14, how were we able to set attributes of the different instances of the Store() class when we have not set the method “store_name()” anywhere within the Store() class?
class Store:
pass
alternative_rocks = Store()
alternative_rocks.store_name = "Alternative Rocks"
isabelles_ices = Store()
isabelles_ices.store_name = "Isabelle's Ices"
Attributes can be given to any object after instantiation. They will only belong to the object they are given to, though, not any of the other instances.
I didn’t really the role of the .fake_key() method.
This was really confusing and it does not explain well how we get to the result in the exercise.
Please elaborate on your question and perhaps we can drum up some examples to guide you along.
This is the solution to the solution:
class Store:
pass
alternative_rocks = Store()
isabelles_ices = Store()
alternative_rocks.store_name = "Alternative Rocks"
isabelles_ices.store_name = "Isabelle's Ices"
But it does not explain how the .store_name got there. They were never declared or anything. Or what is the use for them.
It is a fabrication of the author, just as it would be if it were written into the class in an __init__()
method, which would more likely be the case in a normal sense.
The exercise demonstrates that we can define and instantiate a class even with bare bones code (the minimum required), as shown above. It also demonstrates how we can give one or more instances an attribute apart from the class definition.
If we dig a little deeper, we learn that even class variables can be defined and added later.
>>> Store.store_name = "Big Box"
>>> store1 = Store()
>>> store1.store_name
'Big Box'
>>> store2 = Store()
>>> store2.store_name
'Big Box'
>>>
The earlier two instances will not be affected. When an attribute is give the same name as the class variable, it overrides it. You’ll learn more about this, presently, so keep on chugging away…