Skip to content

Commit c13323e

Browse files
#8 - python
1 parent 2544f04 commit c13323e

File tree

1 file changed

+368
-0
lines changed

1 file changed

+368
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
#8 { Retos para Programadores } CLASES
2+
"""
3+
* EJERCICIO:
4+
* Explora el concepto de clase y crea un ejemplo que implemente un inicializador,
5+
* atributos y una función que los imprima (teniendo en cuenta las posibilidades
6+
* de tu lenguaje).
7+
* Una vez implementada, créala, establece sus parámetros, modifícalos e imprímelos
8+
* utilizando su función.
9+
*
10+
* DIFICULTAD EXTRA (opcional):
11+
* Implementa dos clases que representen las estructuras de Pila y Cola (estudiadas
12+
* en el ejercicio número 7 de la ruta de estudio)
13+
* - Deben poder inicializarse y disponer de operaciones para añadir, eliminar,
14+
* retornar el número de elementos e imprimir todo su contenido.
15+
16+
"""
17+
18+
# Bibliography reference
19+
# Secrets of the JavaScript Ninja (John Resig, Bear Bibeault, Josip Maras)
20+
# Professional JavaScript for web developers by Matt Frisbie
21+
# Python para todos (Raúl Gonzáles Duque)
22+
# GPT
23+
24+
# Classes and Objects
25+
26+
# To understand this paradigm, we first need to comprehend what a class is and what an object is.
27+
# An object is an entity that groups related state and functionality. The state of the object is defined
28+
# through variables called attributes, while the functionality is modeled through functions known as the object's methods.
29+
30+
# An example of an object could be a car, which would have attributes such as the brand, the number of doors,
31+
# or the type of fuel, and methods such as start and stop. Alternatively, it could be any other combination
32+
# of attributes and methods relevant to our program.
33+
34+
# A class, on the other hand, is a generic template from which to instantiate objects; a template that defines
35+
# what attributes and methods the objects of that class will have.
36+
37+
# The fundamental part of most classes is its constructor, which sets up each instance's initial state
38+
# and handles any parameters that were passed when calling the class.
39+
40+
# In Python, we define a class using the 'class' keyword.
41+
42+
log = print
43+
44+
class User:
45+
def __init__(self, name, nickname, email):
46+
self.name = name
47+
self.nickname = nickname
48+
self.email = email
49+
50+
def greeting(self):
51+
log(f"Hi {self.nickname}. Welcome to this Roadmap for Developers!")
52+
53+
def get_email(self):
54+
if self.email is not None:
55+
return self.email
56+
else:
57+
log('No email set yet!')
58+
return None
59+
60+
def get_name(self):
61+
if self.name is not None:
62+
return self.name
63+
else:
64+
log('No name set yet!')
65+
return None
66+
67+
def get_nickname(self):
68+
if self.nickname is not None:
69+
return self.nickname
70+
else:
71+
log('No nickname set yet!')
72+
return None
73+
74+
def set_name(self, name):
75+
if name:
76+
self.name = name
77+
78+
def set_email(self, email):
79+
if email:
80+
self.email = email
81+
82+
def set_nickname(self, nickname):
83+
if nickname:
84+
self.nickname = nickname
85+
86+
def user_info(self):
87+
log(f"User name: {self.name or 'not set'}, User nickname: {self.nickname or 'not set'}, User email: {self.email or 'not set'}")
88+
89+
90+
# Creating an instance of User
91+
user1 = User('Niko Zen', 'duendeintemporal', '[email protected]')
92+
user1.greeting() # Hi duendeintemporal. Welcome to this Roadmap for Developers!
93+
94+
user1.user_info() # User name: Niko Zen, User nickname: duendeintemporal, User email: [email protected]
95+
96+
user1.set_nickname('psicotrogato')
97+
log(user1.get_nickname()) # psicotrogato
98+
99+
# In Python, we can check the type of a class using the type() function.
100+
log(type(User)) # <class 'type'>
101+
102+
# We can use isinstance() to check if an instance is of a certain class.
103+
log(isinstance(user1, User)) # True
104+
105+
# Class Inheritance
106+
# Inheritance works just like it does in other object-oriented languages: methods defined on the superclass
107+
# are accessible in the extending subclass.
108+
109+
class Log:
110+
def __init__(self):
111+
self.logger = log
112+
self.error_log = log
113+
114+
def log(self, msg):
115+
if msg:
116+
self.logger(msg)
117+
else:
118+
self.error_log('You should provide a message')
119+
120+
121+
# When you extend a class in Python, you must call the superclass constructor using super().
122+
class Greeting(Log):
123+
def __init__(self, msg):
124+
super().__init__()
125+
self.msg = msg
126+
127+
128+
say_hi_people = Greeting('Hi everybody. Welcome to the most weird and lonely place in cyberspace...')
129+
say_hi_people.log(say_hi_people.msg) # Hi everybody. Welcome to the most weird and lonely place in cyberspace...
130+
131+
# Static Methods
132+
# Static methods and properties are defined on the class itself, not on instance objects.
133+
# These are specified in a class definition using the @staticmethod decorator.
134+
135+
class ElectroCat:
136+
@staticmethod
137+
def cat_say():
138+
return 'Miauu'
139+
140+
@property
141+
def cat_think(self):
142+
return "Let's see if there's some lovely gircat over there"
143+
144+
145+
log(ElectroCat.cat_say()) # Miauu
146+
log(ElectroCat().cat_think) # Let's see if there's some lovely gircat over there
147+
148+
# We can see that static properties are not defined on object instances:
149+
mishu = ElectroCat()
150+
# The following lines would raise an AttributeError if uncommented, as static methods are not available on instances.
151+
# log(mishu.cat_say()) # Raises AttributeError
152+
# log(mishu.cat_think) # Raises AttributeError
153+
154+
# However, they are defined on subclasses:
155+
class PoetCat(ElectroCat):
156+
pass
157+
158+
log(PoetCat.cat_say()) # Miauu
159+
log(PoetCat().cat_think) # Let's see if there's some lovely gircat over there
160+
161+
# Getters and setters allow you to define custom behavior for reading and writing a given property on your class.
162+
# In Python, we can use the @property decorator for getters and the @<property_name>.setter decorator for setters.
163+
164+
class Cat:
165+
def __init__(self, name):
166+
self._name = name # Using a private variable
167+
168+
@property
169+
def name(self):
170+
"""Getter for the name property."""
171+
return self._name
172+
173+
@name.setter
174+
def name(self, new_name):
175+
"""Setter for the name property."""
176+
if new_name:
177+
self._name = new_name
178+
else:
179+
log("Name cannot be empty!")
180+
181+
# Example usage of the Cat class with getters and setters
182+
my_cat = Cat("Whiskers")
183+
log(my_cat.name) # Whiskers
184+
185+
my_cat.name = "Fluffy" # Using the setter
186+
log(my_cat.name) # Fluffy
187+
188+
my_cat.name = "" # Attempting to set an empty name
189+
# Output: Name cannot be empty!
190+
191+
# Hidden methods can be indicated by prefixing the method name with an underscore.
192+
class HiddenMethodExample:
193+
def __init__(self):
194+
self._hidden_method = "This is a hidden method"
195+
196+
def _hidden_method_function(self):
197+
return self._hidden_method
198+
199+
hidden_example = HiddenMethodExample()
200+
log(hidden_example._hidden_method_function()) # This is a hidden method
201+
# Note: The method is not truly private, but it's a convention to indicate that it should not be accessed directly.
202+
203+
# Summary
204+
# This code demonstrates the use of classes, inheritance, static methods, and property decorators in Python.
205+
# It also illustrates how to define and use getters and setters, as well as the concept of hidden methods.
206+
207+
# We use private properties in Python classes to avoid infinite recursion in getters and setters
208+
# by referencing the private property instead of the public property.
209+
210+
class GopiElectronica:
211+
def __init__(self, name):
212+
self._name = name # Using a private variable
213+
214+
@property
215+
def name(self):
216+
"""Getter for the name property."""
217+
return self._name
218+
219+
@name.setter
220+
def name(self, new_name):
221+
"""Setter for the name property."""
222+
self._name = new_name
223+
224+
def hidden_method(self):
225+
return 'I will hack you boy'
226+
227+
# Example usage of GopiElectronica
228+
Nicky = GopiElectronica('Nicky')
229+
log(Nicky.name) # Nicky
230+
Nicky.name = 'Samantha'
231+
log(Nicky.name) # Samantha
232+
log(f"{Nicky.name} says: {Nicky.hidden_method()}!") # Samantha says: I will hack you boy!
233+
234+
# Note: In Python, we don't have a direct equivalent to JavaScript's Symbol for hiding methods.
235+
# However, we can use naming conventions (like prefixing with an underscore) to indicate that a method is intended to be private.
236+
237+
# Tips: (relevant info)
238+
# Classes are first-class citizens in Python, meaning they can be passed around as you would any other object or function reference.
239+
240+
# Classes may be defined anywhere a function would, such as inside a list:
241+
class_list = [
242+
type('DynamicClass', (object,), {
243+
'__init__': lambda self, id_: log(f'instance {id_}')
244+
})
245+
]
246+
247+
def create_instance(class_definition, id_):
248+
return class_definition(id_)
249+
250+
foo = create_instance(class_list[0], 3141) # instance 3141
251+
252+
# Similar to an immediately invoked function expression, a class can also be immediately instantiated.
253+
# Because it is a class expression, the class name is optional.
254+
# Create a class dynamically and instantiate it immediately
255+
# Create a class dynamically using type with a different name
256+
bar = type('Bar', (object,), {
257+
'__init__': lambda self, x: log(x) # This lambda will log the value of x
258+
})
259+
260+
# Now create an instance of Bar
261+
p = bar('bar') # This will log 'bar'
262+
263+
# log the instance
264+
log(p) # This will log something like <__main__.Bar object at 0x000002108065EF90>
265+
266+
# Additional Exercises
267+
268+
# QUEUE
269+
class Queue:
270+
def __init__(self, initial_items=None):
271+
self.items = initial_items if isinstance(initial_items, list) else []
272+
273+
def enqueue(self, element):
274+
self.items.append(element)
275+
276+
def dequeue(self):
277+
if self.is_empty():
278+
log("Queue is empty. Cannot dequeue an element.")
279+
return None
280+
return self.items.pop(0)
281+
282+
def peek(self):
283+
if self.is_empty():
284+
log("Queue is empty. Cannot peek.")
285+
return None
286+
return self.items[0]
287+
288+
def empty(self):
289+
self.items = []
290+
291+
def is_empty(self):
292+
return len(self.items) == 0
293+
294+
def size(self):
295+
return len(self.items)
296+
297+
# Example usage of Queue
298+
queue2 = Queue([45, 32, 16])
299+
log('Initial queue2:', queue2.items) # [45, 32, 16]
300+
301+
queue2.enqueue(77)
302+
log('After enqueueing 77:', queue2.items) # [45, 32, 16, 77]
303+
304+
log('Peek:', queue2.peek()) # 45
305+
306+
log('Dequeue:', queue2.dequeue()) # 45
307+
log('After dequeueing:', queue2.items) # [32, 16, 77]
308+
309+
log('Dequeue all elements:')
310+
while not queue2.is_empty():
311+
log('Dequeued:', queue2.dequeue())
312+
# or we can just empty the queue
313+
# queue2.empty()
314+
315+
log('Final queue2:', queue2.items) # []
316+
log('Dequeue from empty queue2:', queue2.dequeue()) # Logs error: Queue is empty. Cannot dequeue an element. & Dequeue from empty queue2: None
317+
318+
# STACK
319+
class Stack:
320+
def __init__(self, initial_items=None):
321+
self.items = initial_items if isinstance(initial_items, list) else []
322+
323+
def push(self, element):
324+
self.items.append(element)
325+
326+
def pop(self):
327+
if self.is_empty():
328+
log("Stack is empty. Cannot pop an element.")
329+
return None
330+
return self.items.pop()
331+
332+
def peek(self):
333+
if self.is_empty():
334+
log("Stack is empty. Cannot peek.")
335+
return None
336+
return self.items[-1]
337+
338+
def empty(self):
339+
self.items = []
340+
341+
def is_empty(self):
342+
return len(self.items) == 0
343+
344+
def size(self):
345+
return len(self.items)
346+
347+
# Example usage of Stack
348+
stack2 = Stack([55, 76, 98, 100])
349+
log('Initial stack2:', stack2.items) # [55, 76, 98, 100]
350+
351+
stack2.push(32)
352+
log('After pushing 32:', stack2.items) # [55, 76, 98, 100, 32]
353+
354+
log('Peek:', stack2.peek()) # 32
355+
356+
log('Pop:', stack2.pop()) # 32
357+
log('After popping:', stack2.items) # [55, 76, 98, 100]
358+
359+
log('Pop all elements:')
360+
while not stack2.is_empty():
361+
log('Popped:', stack2.pop())
362+
# or we can just empty the stack
363+
# stack2.empty()
364+
365+
log('Final stack2:', stack2.items) # []
366+
log('Pop from empty stack2:', stack2.pop()) # Logs error: Stack is empty. Cannot pop an element. & Pop from empty stack2: None
367+
368+

0 commit comments

Comments
 (0)