More on Python class, attributes and naming.
I visited the learncodethehardway forum, and someone had an excellent question.
There was a bit of an exercise where there was some confusion because of naming and where/what attributes were being set, what code was actually doing the work within the script.
I made these two tiny examples to show the user what was going on in the python class.
I wanted to put it in the blog for anyone else that may have some confusion with what is going on, because I know when I started, I sure did struggle with it.
I'll put comments in the code to explain:
~~~~~~~~~~~ Example 1 ~~~~~~~~~~
--start code block--
--End code block--
~~~~~~~~~~~~~~~~~~~~~~~~~
Now what does it look like if I peek into sillyness's dictionary where the namespaces are being held?
I add this line of code at the end of the above script:
print(sillyness.__dict__)
This line will print in my console:
{'something': <__main__.Hello object at 0x7f71869600b8>}
Here is a great article about class attributes:
https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide
Now for the next example, this is where the trouble started. It is a mock/ much simpler version of what was in the exercise code:
~~~~~~~~~~ Example 2 ~~~~~~~~~~~~
-- Start code block --
--End code block--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The trouble is that in this one, you can't really see by just looking at that Spam class, that the Hello() class has been passed in under a new name.
It is being initiated at the bottom as 'something' ,
then in Spam being renamed. When really it's still the active(initiated) Hello class the whole time.
Another issue:
Attributes are not the same as inheritance. But they sure look the same.
The difference which I think caused some trouble is that when you make this sillyness = Spam(something) it looks like inheritance, but inheritance is done when you write the class itself.
If it was inheriting, it would look more like this:
~~~~~~~~ Example 3 ~~~~~~~~~
--- Start code block ---
--End code block ---
~~~~~~~~~~~~~~~~~~~~~
So in conclusion,
* An attribute can be almost anything, even a class
* An attribute is not 'inherited', it is created and placed in the class dictionary
under a new name, if you've chosen to give it a new name,
when the class is initialized: self.something = something
* To trace down where the work is being done, if your attribute does something
like self.anAttribute.do_some_function(), your attribute is a class calling a
function from it's code. The < . > is a call to a something. It's telling the
machine to look up this thing, and execute some action.
In the example, Spam's function 'spam()' is just backpacking the Hello's function: 'Hiya()' and I think this over naming and variable creating is what really made it hard to follow (Example 2).
*I'm not sure what to call it when one class borrows a method of another class.
So I'm calling it backpacking. I believe piggybacking is already used. *
As always, drop a comment, question, anything.
May the spam be ever in your flavor!
There was a bit of an exercise where there was some confusion because of naming and where/what attributes were being set, what code was actually doing the work within the script.
I made these two tiny examples to show the user what was going on in the python class.
I wanted to put it in the blog for anyone else that may have some confusion with what is going on, because I know when I started, I sure did struggle with it.
I'll put comments in the code to explain:
~~~~~~~~~~~ Example 1 ~~~~~~~~~~
--start code block--
class Spam(object):
def __init__(self):
# this is an attribute. It can be anything-- Even a class
self.something = Hello()
def spam(self):
#self.something is an instance of Hello class
self.something.hiYa()
class Hello(object):
#This is a python object that holds a method
def hiYa(self):
print("Hello")
#Initiate Spam
sillyness = Spam()
#call Spam's function spam.
sillyness.spam()
~~~~~~~~~~~~~~~~~~~~~~~~~
Now what does it look like if I peek into sillyness's dictionary where the namespaces are being held?
I add this line of code at the end of the above script:
print(sillyness.__dict__)
This line will print in my console:
{'something': <__main__.Hello object at 0x7f71869600b8>}
Here is a great article about class attributes:
https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide
Now for the next example, this is where the trouble started. It is a mock/ much simpler version of what was in the exercise code:
~~~~~~~~~~ Example 2 ~~~~~~~~~~~~
-- Start code block --
class Spam(object):
def __init__(self, another_something):
#This is where what the original value of the attribute
# gets messy. It's a chair, it's a seat, it's a recliner, it's nap_time.
self.another_something = another_something
def spam(self):
# notice you don't even have to use self but you should.
#self.another_something.hiYa() works here too.
another_something.hiYa()
# Initiated Hello now has Three names:
# something, another_something, self.another_something.
# This just feels messy and confusing.
class Hello(object):
def hiYa(self):
print("Hello")
something = Hello()
sillyness = Spam(something)
sillyness.spam()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The trouble is that in this one, you can't really see by just looking at that Spam class, that the Hello() class has been passed in under a new name.
It is being initiated at the bottom as 'something' ,
then in Spam being renamed. When really it's still the active(initiated) Hello class the whole time.
Another issue:
Attributes are not the same as inheritance. But they sure look the same.
The difference which I think caused some trouble is that when you make this sillyness = Spam(something) it looks like inheritance, but inheritance is done when you write the class itself.
If it was inheriting, it would look more like this:
~~~~~~~~ Example 3 ~~~~~~~~~
--- Start code block ---
## ---- Inheritance ---- ##
class Hello(object):
def __init__(self):
self.message = "Howdy!"
def hiYa(self):
print(self.message)
class Spam(Hello):
def __init__(self, something):
Hello.__init__(self)
self.something = something
def spam(self):
print(self.message, self.something)
something = "Nice to meet you."
sillyness = Spam(something)
sillyness.spam()
# Wow, even more variables and declarations to sort out!
~~~~~~~~~~~~~~~~~~~~~
So in conclusion,
* An attribute can be almost anything, even a class
* An attribute is not 'inherited', it is created and placed in the class dictionary
under a new name, if you've chosen to give it a new name,
when the class is initialized: self.something = something
* To trace down where the work is being done, if your attribute does something
like self.anAttribute.do_some_function(), your attribute is a class calling a
function from it's code. The < . > is a call to a something. It's telling the
machine to look up this thing, and execute some action.
In the example, Spam's function 'spam()' is just backpacking the Hello's function: 'Hiya()' and I think this over naming and variable creating is what really made it hard to follow (Example 2).
*I'm not sure what to call it when one class borrows a method of another class.
So I'm calling it backpacking. I believe piggybacking is already used. *
As always, drop a comment, question, anything.
May the spam be ever in your flavor!
Comments
Post a Comment