Skip to content

Commit 7610272

Browse files
committed
Long Updation
1 parent d15b7f8 commit 7610272

File tree

15 files changed

+2419
-1131
lines changed

15 files changed

+2419
-1131
lines changed

Concepts/01_Intro/source.py renamed to Concepts/01_Intro/01_General/source.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
''' This file provides the general introduction about the pyrhon '''
3+
''' This file provides the general introduction about the python '''
44

55
# Variable declaration
66
# VAR = 20 # Assigning value
@@ -20,13 +20,13 @@
2020
# --> Convey a special meaning to the compiler/interpreter
2121
# --> Each keyword have a special meaning and a specific operation
2222
# --> Keyword cannot be used as a variable
23-
# False class finally is return
24-
# None continue for lambda try
25-
# True def from nonlocal while
26-
# and del global not with
27-
# as elif if or yield
28-
# assert else import pass
29-
# break except in raise
23+
# False class finally is return
24+
# None continue for lambda try
25+
# True def from nonlocal while
26+
# and del global not with
27+
# as elif if or yield
28+
# assert else import pass
29+
# break except in raise
3030

3131

3232
# Identifiers
@@ -48,6 +48,7 @@
4848
# - Special literal
4949

5050
# String Literals
51+
print('---- String Literals ----')
5152
FNAME = "Silver"
5253
LNAME = "Taurus"
5354
print(FNAME + ' ' + LNAME)
@@ -97,4 +98,4 @@
9798
# - Sets
9899

99100
# User-Defined Classes who do not have any medium to change their internal state
100-
# are also considered immutables. While if they change their internal state they are mutables.
101+
# are also considered immutables. While if they change their internal state they are mutables.
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
#! /usr/bin/env python3
2+
3+
''' Python script for introduction to classes and objects '''
4+
5+
#---- Use of basic built-in functions and operator overloading ----
6+
class Rectangle:
7+
def __init__(self, width, height):
8+
# here, self is customary used variable name and not a fixed usable keyword (hence we can write anything in place of self)
9+
self.width = width
10+
self.height = height
11+
12+
def area(self):
13+
return self.width * self.height
14+
15+
def perimeter(self):
16+
return 2 * (self.width + self.height)
17+
18+
def __str__(self):
19+
return 'Rectangle: width={}, height={}'.format(self.width, self.height)
20+
21+
# Overloading built-in function repr()
22+
def __repr__(self):
23+
return 'Rectangle({}, {})'.format(self.width, self.height)
24+
25+
# Overloading the == operator
26+
def __eq__(self, other):
27+
if isinstance(other, Rectangle):
28+
return (self.width, self.height) == (other.width, other.height)
29+
else:
30+
return False
31+
32+
# Overloading the < operator
33+
def __lt__(self, other):
34+
if isinstance(other, Rectangle):
35+
return self.area() < other.area()
36+
else:
37+
# we didn't raise NotImplemented, we returned it
38+
return NotImplemented
39+
40+
r1 = Rectangle(10, 20)
41+
print('\n\n---- Classes and Objects ----')
42+
print(r1.area())
43+
print(r1.perimeter())
44+
print(str(r1))
45+
print(repr(r1)) # This is the case of - when we just write r1 in the interactive console and run it - and it gives the - repr(object).
46+
47+
r2 = Rectangle(10 ,20)
48+
print(r1 == r2)
49+
print(r1 == 100)
50+
print(r1 < r2)
51+
print(r1 > r2) # will give the correct output even though __gt__ method is not defined, as in this case python first sees for __gt__ method when not found will
52+
# find its negation that is __lt__ method which is implemented and hence will use the ouput from it and negate it and hance provide the correct output.
53+
# But this will not gonna happen with >== or <== as their complement is not defined.
54+
r1.width = 100
55+
print(repr(r1))
56+
57+
del Rectangle
58+
59+
60+
61+
#---- Using getters and setters ----
62+
class Rectangle:
63+
def __init__(self, width, height):
64+
self._width = width # using one underscore is just customary to tell the other user that these are private and not use them directly
65+
self._height = height # and in-place use the getters and setters method.
66+
67+
def area(self):
68+
return self._width * self._height
69+
70+
def perimeter(self):
71+
return 2 * (self._width + self._height)
72+
73+
def get_width(self):
74+
return self._width
75+
76+
def set_width(self, width):
77+
if width <= 0:
78+
raise ValueError('Width must be positive!!!')
79+
else:
80+
self._width = width
81+
82+
def get_height(self):
83+
return self._height
84+
85+
def set_heith(self, height):
86+
self._height = height
87+
def get_width(self):
88+
return self._width
89+
90+
def set_width(self, width):
91+
if width <= 0:
92+
raise ValueError('Width must be positive!!!')
93+
else:
94+
self._width = width
95+
96+
def get_height(self):
97+
return self._height
98+
99+
def set_heith(self, height):
100+
self._height = height
101+
102+
def __str__(self):
103+
return 'Rectangle: width={}, height={}'.format(self._width, self._height)
104+
105+
def __repr__(self):
106+
return 'Rectangle({}, {})'.format(self._width, self._height)
107+
108+
def __eq__(self, other):
109+
if isinstance(other, Rectangle):
110+
return (self._width, self._height) == (other._width, other._height)
111+
else:
112+
return False
113+
114+
def __lt__(self, other):
115+
if isinstance(other, Rectangle):
116+
return self.area() < other.area()
117+
else:
118+
return NotImplemented
119+
120+
121+
# Now for controlling the access for our encapsulated data, we generally uses getters and setters. Suppose for this case we don't need negative value for width as it is not possible.
122+
123+
# As we have the getters and setters, so the people should be accessing the width and height using get_width and set_width methods and not directly by obj._width or obj_height.
124+
# If here, we will try to get obj.width or obj.height it will give us `Attribute Error`, but if we will try to set value obj.width = -100 or obj.height= -100 then it will create a new attribute
125+
# of these names. This process is called Monkey Patching.
126+
127+
# But if we have chagned the attributes to customary private notations, and forces to use getters ans setters then, if the people have written the code as obj.width = 100 or print(obj.width), then
128+
# the code will break at those points and they have to change their code.
129+
130+
r = Rectangle(10, 20)
131+
print(repr(r))
132+
# print(r.width) --> will give the `Attribute Error`
133+
r.width = 100 # This is Monkey Patching and not setting of width attribute value as the attribute is _width whose value will remain same.
134+
print(repr(r))
135+
r.set_width = 100
136+
print(repr(r))
137+
138+
del Rectangle
139+
140+
141+
142+
#---- Solution for breaking of code problem ----
143+
# - Don't force the getters and setters until they are providing some extra functionality like in this case of width and height we have extra functionalty that is, width and height cannot
144+
# be negative.
145+
# - Also for those attributes, for whom we need to use setters and getters we make it transparent without letting the user know that a setter is being used, as the user will be directly accessing
146+
# using name but in background the setter or getter will be runnig.
147+
class Rectangle:
148+
def __init__(self, width, height):
149+
self._width = width
150+
self._height = height
151+
152+
def area(self):
153+
return self._width * self._height
154+
155+
def perimeter(self):
156+
return 2 * (self._width + self._height)
157+
158+
# property is use to make the property to be passed through a getter
159+
@property
160+
def width(self):
161+
''' This is a getter method which is marked as a property using property decorator'''
162+
return self._width
163+
164+
@property
165+
def height(self):
166+
''' This is getter method which is marked as property using property decorator '''
167+
return self._height
168+
169+
# Now since we have the width and height as a property, we can use the proprty.setter to mark that the property
170+
# is now being set via setter
171+
@width.setter
172+
def width(self, width):
173+
if width <= 0:
174+
raise ValueError('Width must be positive!!!')
175+
else:
176+
self._width = width
177+
178+
@height.setter
179+
def height(self, height):
180+
if height <= 0:
181+
raise ValueError('Height must be positive!!!')
182+
else:
183+
self._height= height
184+
185+
def __str__(self):
186+
return 'Rectangle: width={}, height={}'.format(self._width, self._height)
187+
188+
def __repr__(self):
189+
return 'Rectangle({}, {})'.format(self._width, self._height)
190+
191+
def __eq__(self, other):
192+
if isinstance(other, Rectangle):
193+
return (self._width, self._height) == (other._width, other._height)
194+
else:
195+
return False
196+
197+
def __lt__(self, other):
198+
if isinstance(other, Rectangle):
199+
return self.area() < other.area()
200+
else:
201+
return NotImplemented
202+
203+
# Since we have made the getters and setters as the property we can directly use them using object without calling them using paranthesis.
204+
# So, if the name of the getters and setters method are same as that of property without _, then the problem of breaking of code will resolve as
205+
# we can get or set the width and height using the getters and setters by using just the name of the property.
206+
207+
r = Rectangle(10, 20)
208+
print(r.width)
209+
r.width = 100
210+
print(repr(r))
211+
212+
# Now the above code works fine for most of the things, but there is still a problem that initialisation method can take negative values of width or height.
213+
# So what can i do is:
214+
# - Use exception handling
215+
# or
216+
# - Use setters in __init__
217+
218+
del Rectangle
219+
220+
221+
222+
#---- Using Setters for initialisation ----
223+
class Rectangle:
224+
def __init__(self, width, height):
225+
self.width = width # setter is called
226+
self.height = height # setter is called
227+
228+
def area(self):
229+
return self._width * self._height
230+
231+
def perimeter(self):
232+
return 2 * (self._width + self._height)
233+
234+
@property
235+
def width(self):
236+
''' This is a getter method which is marked as a property using property decorator'''
237+
return self._width
238+
239+
@property
240+
def height(self):
241+
''' This is getter method which is marked as property using property decorator '''
242+
return self._height
243+
244+
@width.setter
245+
def width(self, width):
246+
if width <= 0:
247+
raise ValueError('Width must be positive!!!')
248+
else:
249+
self._width = width
250+
251+
@height.setter
252+
def height(self, height):
253+
if height <= 0:
254+
raise ValueError('Height must be positive!!!')
255+
else:
256+
self._height = height
257+
258+
def __str__(self):
259+
return 'Rectangle: width={}, height={}'.format(self._width, self._height)
260+
261+
def __repr__(self):
262+
return 'Rectangle({}, {})'.format(self._width, self._height)
263+
264+
def __eq__(self, other):
265+
if isinstance(other, Rectangle):
266+
return (self._width, self._height) == (other._width, other._height)
267+
else:
268+
return False
269+
270+
def __lt__(self, other):
271+
if isinstance(other, Rectangle):
272+
return self.area() < other.area()
273+
else:
274+
return NotImplemented
275+
276+
# r = Rectangle(10, -20) --> will give you ValueError
277+
r = Rectangle(10, 20)
278+
print(r._width)
279+
print(r.width)
280+
print(r.area())

0 commit comments

Comments
 (0)