In this we will look into some of the advanced features which Python provide
In this we will look onto, how Python allows us to take advantage of operators in our classes. Python is largely objects and methods call on objects and this even goes on even when its hidden by some convenient syntax.
>>> var1 = 'Hello' >>> var2 = ' World!' >>> var1 + var2 'Hello World!' >>> >>> var1.__add__(var2) 'Hello World!' >>> num1 = 45 >>> num2 = 60 >>> num1.__add__(num2) 105 >>> var3 = ['a', 'b'] >>> var4 = ['hello', ' John'] >>> var3.__add__(var4) ['a', 'b', 'hello', ' John']
So if we have to add magic method __add__ to our own classes, could we do that too. Let’s try to do that.
We have a class called Sumlist which has a contructor __init__ which takes list as an argument called my_list.
class SumList(object): def __init__(self, my_list): self.mylist = my_list def __add__(self, other): new_list = [ x + y for x, y in zip(self.mylist, other.mylist)] return SumList(new_list) def __repr__(self): return str(self.mylist) aa = SumList([3,6, 9, 12, 15]) bb = SumList([100, 200, 300, 400, 500]) cc = aa + bb # aa.__add__(bb) print(cc) # should gives us a list ([103, 206, 309, 412, 515])
[103, 206, 309, 412, 515]
But there are many methods which are internally managed by others magic methods. Below are some of them,
'abc' in var # var.__contains__('abc') var == 'abc' # var.__eq__('abc') var[1] # var.__getitem__(1) var[1:3] # var.__getslice__(1, 3) len(var) # var.__len__() print(var) # var.__repr__()
Classes can also inherit from built-in types this means inherits from any built-in and take advantage of all the functionality found there.
In below example we are inheriting from dictionary but then we are implementing one of its method __setitem__. This (setitem) is invoked when we set key and value in the dictionary. As this is a magic method, this will be called implicitly.
class MyDict(dict): def __setitem__(self, key, val): print('setting a key and value!') dict.__setitem__(self, key, val) dd = MyDict() dd['a'] = 10 dd['b'] = 20 for key in dd.keys(): print('{0} = {1}'.format(key, dd[key]))
setting a key and value! setting a key and value! a = 10 b = 20
Let’s extend our previous example, below we have called two magic methods called __getitem__ and __setitem__ better invoked when we deal with list index.
# Mylist inherits from 'list' object but indexes from 1 instead for 0! class Mylist(list): # inherits from list def __getitem__(self, index): if index == 0: raise IndexError if index > 0: index = index - 1 return list.__getitem__(self, index) # this method is called when # we access a value with subscript like x[1] def __setitem__(self, index, value): if index == 0: raise IndexError if index > 0: index = index - 1 list.__setitem__(self, index, value) x = Mylist(['a', 'b', 'c']) # __init__() inherited from builtin list print(x) # __repr__() inherited from builtin list x.append('HELLO'); # append() inherited from builtin list print(x[1]) # 'a' (Mylist.__getitem__ cutomizes list superclass # method. index is 1, but reflects 0! print (x[4]) # 'HELLO' (index is 4 but reflects 3!
['a', 'b', 'c'] a HELLO
In above example, we set a three item list in Mylist and implicitly __init__ method is called and when we print the element x, we get the three item list ([‘a’,’b’,’c’]). Then we append another element to this list. Later we ask for index 1 and index 4. But if you see the output, we are getting element from the (index-1) what we have asked for. As we know list indexing start from 0 but here the indexing start from 1 (that’s why we are getting the first item of the list).
In this we will look into names we’ll used for variables especially private variables and conventions used by Python programmers worldwide. Although variables are designated as private but there is not privacy in Python and this by design. Like any other well documented languages, Python has naming and style conventions that it promote although it doesn’t enforce them. There is a style guide written by “Guido van Rossum” the originator of Python, that describe the best practices and use of name and is called PEP8. Here is the link for this, https://www.python.org/dev/peps/pep-0008/
PEP stands for Python enhancement proposal and is a series of documentation that distributed among the Python community to discuss proposed changes. For example it is recommended all,
These are just the recommendation, you can vary if you like. But as most of the developers follows these recommendation so might me your code is less readable.
We can follow the PEP recommendation we it allows us to get,
In Python, when we are dealing with modules and classes, we designate some variables or attribute as private. In Python, there is no existence of “Private” instance variable which cannot be accessed except inside an object. Private simply means they are simply not intended to be used by the users of the code instead they are intended to be used internally. In general, a convention is being followed by most Python developers i.e. a name prefixed with an underscore for example. _attrval (example below) should be treated as a non-public part of the API or any Python code, whether it is a function, a method or a data member. Below is the naming convention we follow,
Public attributes or variables (intended to be used by the importer of this module or user of this class) −regular_lower_case
Private attributes or variables (internal use by the module or class) −_single_leading_underscore
Private attributes that shouldn’t be subclassed −__double_leading_underscore
Magic attributes −__double_underscores__(use them, don’t create them)
class GetSet(object): instance_count = 0 # public __mangled_name = 'no privacy!' # special variable def __init__(self, value): self._attrval = value # _attrval is for internal use only GetSet.instance_count += 1 @property def var(self): print('Getting the "var" attribute') return self._attrval @var.setter def var(self, value): print('setting the "var" attribute') self._attrval = value @var.deleter def var(self): print('deleting the "var" attribute') self._attrval = None cc = GetSet(5) cc.var = 10 # public name print(cc._attrval) print(cc._GetSet__mangled_name)
setting the "var" attribute 10 no privacy!