I'll give a high level answer to your questions but I recommend to take a look at the Python documentation to get a more in-depth answer.
1) There are essentially two types of attributes an object can have. Objects can have instance attributes
that are assigned on a per object basis and class attributes
that all instances of that object have access to.
class Employee(object):
has_benefits = True # class attribute
def __init__(self, name, badge_number):
self.name = name # instance attribute
self.badge_number = badge_number # instance attribute
>> e1 = Employee('bob', 123)
>> e1.name
>> 'bob'
>> e1.has_benefits
>> True
>>
>> e2 = Employee('sarah', 456)
>> e2.name
>> 'sarah'
>> e2.has_benefits
>> True
In this example, every Employee instance created has instance attributes name
and badge_number
which are specific to that instance, but notice how every Employee instance has access to the class attribute has_benefits
which is set to True
for all Employees.
A function
is some code that can be called by it's name, whereas a method
is some code that can be called by it's name that is associated with an object. There is also an instance method
which accepts the self
argument as it's first parameter
def show_something():
print('Show something')
class MyClass(object):
# method
def display_something():
print('Display something')
# instance method
def print_something(self):
print('Print something')
>> show_something()
>> 'Show something'
>>
>> MyClass.display_something()
>> 'Display something'
>>
>> mc = MyClass()
>> mc.print_something()
>> 'Print something'
Notice how the function show_something
is just some code that we could call by name. Also, notice how the method display_something
is bound to our class object and the instance method print_something
is bound to an instance of our object. mc.print_something()
is the same as MyClass.print_something(mc)
2) Running dir()
on an object returns a list of all of the object's attributes. Some attributes are considered special attributes that are surrounded by double underscores. Some attributes are callable which we can determine by passing the attribute to the built-in function callable()
which will return True
if the attribute is callable, False
otherwise.
Attributes without the surrounding double underscores are also attributes and methods can be attributes too. __abs__
gets called when you run the abs()
built-in function which returns the absolute value of the object passed-in. bit_length
is a method that returns the number of bits which represent the passed-in object. And yes, you access these attributes with the . (dot) syntax.
>> my_num = 5
>> my_num.real
>> 5
>> callable(my_num.bit_length)
>> True
>> my_num.bit_length()
>> 3
>> my_num.__class__
>> <class 'int'>
3) Lastly, we can define an object that implements some special methods that get used by Python when we run specific actions such as membership testing and getting the length of a collection. I'll show some basic examples:
class MyCollection(object):
def __init__(self, data):
self.my_data = data
def __contains__(self, item):
return item in self.my_data
def __len__(self):
return len(self.my_data)
def __iter__(self):
for item in self.my_data:
yield item
def __add__(self, rhs):
if not isinstance(rhs, MyCollection):
return NotImplemented
return self.my_data + rhs.my_data
def __eq__(self, rhs):
if not isinstance(rhs, MyCollection):
return NotImplemented
return self.my_data == rhs.my_data
def __ne__(self, rhs):
if not isinstance(rhs, MyCollection):
return NotImplemented
return self.my_data != rhs.my_data
Give it a try:
>> mc1 = MyCollection([1,2,3,4,5])
>> mc2 = MyCollection([6,7,8,9])
>> mc3 = MyCollection([1,2,3,4,5])
>>
>> 3 in mc1 # calls __contains__
>> True
>>
>> len(mc1) # calls __len__
>> 5
>>
>> [item for item in mc1] # calls __iter__
>> [1,2,3,4,5]
>>
>> mc1 + mc2 # calls __add__
>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>
>> mc1 == mc2 # calls __eq__
>> False
>>
>> mc1 != mc2 # calls __ne__
>> True
>>
>> mc1 == mc3 # calls __eq__
>> True
I hope this helped!