From b7913b5f7cac35ecd7a59c1a4e91605559c8bf48 Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 18 Nov 2022 19:11:44 +0200 Subject: [PATCH 1/7] Create file Classes.md(2) --- Object_Oriented_Programming/Classes.md | 470 +++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 Object_Oriented_Programming/Classes.md diff --git a/Object_Oriented_Programming/Classes.md b/Object_Oriented_Programming/Classes.md new file mode 100644 index 0000000..b8a0dca --- /dev/null +++ b/Object_Oriented_Programming/Classes.md @@ -0,0 +1,470 @@ +# What is a Python Class? + +_A Python class is like an outline for creating a new object. An object is anything that you wish +to manipulate or change while working through the code. Every time a class object is instantiated, +which is when we declare a variable, a new object is initiated from scratch. Class objects can be used over and over +again whenever needed._ + +_A class is usually modeled after a Noun. Classes are things. So we might make a class that represents a Person, House, +Vehicle, or Animal. These are all common examples to use when learning about classes. For us, we will create a Vehicle +class. +What information would we associate with a vehicle, and what behavior would it have? A vehicle may have a type, brand, +model and so on. +This type of information is stored in python variables __called attributes__. These things also have behaviors. A +Vehicle can drive, stop, +honk its horn, and so on. Behaviors are contained in functions and a function that is part of a class is called a +method._ + ++ Example: + +```python +class Vehicle: + def __init__(self, brand, model, type): + self.brand = brand + self.model = model + self.type = type + self.gas_tank_size = 14 + self.fuel_level = 0 + + def fuel_up(self): + self.fuel_level = self.gas_tank_size + print('Gas tank is now full.') + + def drive(self): + print(f'The {self.model} is now driving.') + +``` + +# Attributes + +### Class Attributes + +_Class attributes are attributes which are owned by the class itself. They will be shared by all the instances +of the class. Therefore they have the same value for every instance. We define class attributes outside all the methods, +usually they are placed at the top, right below the class header._ + ++ Example: + +```python +class A: + a = "I am a class attribute!" +``` + +### Instance Attributes + +_Instance Attributes are unique to each object, (an instance is another name for an object). +Here, any animal object we create will be able to store its name and age. We can change either attribute of either +animal, +without affecting any other animal objects we’ve created._ + ++ Example: + +```python +class Animal: + + def __init__(self, name, age): + self.name = name + self.age = age +``` + +| Instance Attributes | Class Attributes | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| an instance attribute defined inside the constructor. | a class attribute defined outside the constructor. | +| only accessible from the scope of an object.| accessible as both a property of the class and as a property of objects, as it is shared between all of them. | + +# Methods + +_Properties of the object are defined by the attributes and the behavior is defined using methods. +These methods are defined inside a class. These methods are the reusable piece of code that can be +invoked/called at any point in the program._ + +### Class constructor \_\_init__ + +_The properties that all Animals objects must have are defined in a method called +.__init__(). Every time a new Dog object is created, .__init__() sets the initial +state of the object by assigning the values of the object’s properties. That is, +.__init__() initializes each new instance of the class._ + +### Class constructor \_\_init__ + +_The properties that all Animals objects must have are defined in a method called +.__init__(). Every time a new Dog object is created, .__init__() sets the initial +state of the object by assigning the values of the object’s properties. That is, +.__init__() initializes each new instance of the class._ + ++ Example: + +```python +class Animals: + def __init__(self, name, age): + self.name = name + self.age = age +``` + +### \_\_new__ method !!!!!!!!!!!!!!! + +_When you create an instance of a class, Python first calls the __new__() method to create the object and +then calls the __init__() method to initialize the object’s attributes._ + +_The __new__() is a static method of the object class. It has the following signature:_ + ++ Example: + +```python +object.__new__( + + +class , * args, ** kwargs) +``` + +_The first argument of the __new__ method is the class of the new object that you want to create._ + +_The *args and **kwargs parameters must match the parameters of the __init__() of the class. However, the __new__() +method does use them._ + ++ Example: + +```python +class Animal: + def __new__(cls, name): + print(f'Creating a new {cls.__name__} object...') + obj = object.__new__(cls) + return obj + + def __init__(self, name): + print(f'Initializing the animal object...') + self.name = name + + +cat = Animal('Jimmi') +``` + +### Instance methods + +_Instance method are methods which require an object of its class to be created before it can be called. +To invoke a instance method, we have to create an Object of the class in which the method is defined._ + ++ Use the def keyword to define an instance method in Python. ++ Use self as the first parameter in the instance method when defining it. The self parameter refers to the current + object. ++ Using the self parameter to access or modify the current object attributes. + ++ Example: + +```python +class Animal: + # constructor + def __init__(self, name, age): + # Instance variable + self.name = name + self.age = age + + # instance method + def show(self): + print('Name:', self.name, 'Age:', self.age) + + +cat = Animal('Jimmi') +# call instance method +cat.show() +``` + +# Class method and static method in Python + +_The class method in Python is a method, which is bound to the class but not the object of that class. The static +methods are also same but there are some basic differences. For class methods, we need to specify @classmethod +decorator, and for static method @staticmethod decorator is used._ + +_Syntax for Class Method:_ + ++ Example: + +```python +class my_class: + @classmethod + def function_name(cls, arguments): + # Function Body + return value +``` + +_Syntax for Static Method._ + ++ Example: + +```python +class my_class: + @staticmethod + def function_name(arguments): + # Function Body + return value +``` + +# Добавить в сравнение ещё методы с self, как-то красивее дописать + +| Class Method | Static Method | +|-------------------------------------------------------------|:-----------------------------------------------------------:| +| The class method takes cls (class) as first argument. | The static method does not take any specific parameter. | +| Class method can access and modify the class state. | Static Method cannot access or modify the class state. | +| The class method takes the class as parameter to know about the state of that class. | Static methods do not know about class state. These methods are used to do some utility tasks by taking some parameters. | +| @classmethod decorator is used here. | @staticmethod decorator is used here. | + +# Magic Methods + +_Magic methods are special methods in python that have double underscores on both sides of the method name. +Magic methods are predominantly used for operator overloading. Operator overloading means provided additional +functionality to the operators, the python implicitly invokes the magic methods to provide additional +functionality to it_ + ++ \_\_add__ method ++ + +_the \_\_add__ method is a magic method which gets called when we add two numbers using the + operator. Consider the +following example_ + ++ Example: + +```python +class ADD: + def __init__(self, string_): + self.string_ = string_ + + def __add__(self, string2): + return self.string_ + string2 + + +ex = Str("Hello") +print(instance1 + " Folks") +``` + ++ \_\_str__() method + +_\_\_str__(). It is overridden to return a printable string representation of any user defined class._ + ++ Example: + +```python +class Person: + def __init__(self, name, age): + self.name = name + self.age = age + + def __str__(self): + return f"{self.name}({self.age})" + + +p1 = Person("John", 36) + +print(p1) +``` + ++ \_\_getitem__ and \_\_setitem__ magic method + +_\_\_getitem__ method is used to get an item from the invoked instances’ attribute. \_\_getitem__ is commonly used with +containers like list, tuple, etc._ + ++ Example: + +```python +class A: + def __init__(self, item): + self.item = item + + def __getitem__(self, index): + return self.item[index] + + +a = A([1, 2]) +print(f"First item: {a[0]}") +print(f"Second item: {a[1]}") + +``` + ++ Example: + +```python +class Employee: + def __new__(cls): + print("__new__ magic method is called") + inst = object.__new__(cls) + return inst + + +def __init__(self): + print("__init__ magic method is called") + self.name = 'Satya' +``` + +_\__lt_\_, _\_gt_\_, _\_le_\_, _\_ge_\_, _\_eq_\_, and _\_ne_\_ magic methods_ + +_Comparative operators can be used to compare between the object’s attributes._ + ++ Example: __new__() + +```python +class Comparison: + def __init__(self, a): + self.a = a + + def __lt__(self, object2): + return self.a < object2.a + + def __gt__(self, object2): + return self.a > object2.a + + def __le__(self, object2): + return self.a <= object2.a + + def __ge__(self, object2): + return self.a >= object2.a + + def __eq__(self, object2): + return self.a == object2.a + + def __ne__(self, object2): + return self.a != object2.a + + +a = Comparison(1) +b = Comparison(2) +print( + a < b, + a > b, + a <= b, + a >= b, + a == b, + a != b +) +``` + +| Operator Magic Methods | Description | +|---------------------------------|-----| +| \__add__(self, other) |To get called on add operation using + operator | +| \__sub__(self, other) |To get called on subtraction operation using - operator. | +| \__mul__(self, other) |To get called on multiplication operation using * operator. | +| \__floordiv__(self, other) |To get called on floor division operation using // operator. | +| \__truediv__(self, other) | To get called on division operation using / operator. | +| \__mod__(self, other) | To get called on modulo operation using % operator. | +| \__pow__(self, other[, modulo]) | To get called on calculating the power using ** operator. | + +### Type conversion magic methods + +_Python also has an array of magic methods designed to implement behavior for built in type conversion functions like +float(). Here they are:_ + +``` +__int__(self) +Implements type conversion to int. + +__long__(self) +Implements type conversion to long. + +__float__(self) +Implements type conversion to float. + +__complex__(self) +Implements type conversion to complex. + +__oct__(self) +Implements type conversion to octal. + +__hex__(self) +Implements type conversion to hexadecimal. + +__index__(self) +Implements type conversion to an int when the object is used in a slice expression. If you define a custom numeric type that might be used in slicing, you should define __index__. + +__trunc__(self) +Called when math.trunc(self) is called. __trunc__ should return the value of `self truncated to an integral type (usually a long). + +__coerce__(self, other) +Method to implement mixed mode arithmetic. __coerce__ should return None if type conversion is impossible. Otherwise, it should return a pair (2-tuple) of self and other, manipulated to have the same type. +``` + +_In the following example, you create a custom class Data and overwrite the __complex__() +magic method so that it returns a complex number (33+11j) when trying to call complex(x) on a custom Data object._ + ++ Example: + +```python +class Data: + def __complex__(self): + return (42+21j) +x = Data() +res = complex(x) +print(res) +# (33+11j) +``` + +### Controlling Attribute Access + +_Python accomplishes a great deal of encapsulation through "magic", instead of explicit modifiers for methods or +fields._ + +``` +__getattr__(self, name) +You can define behavior for when a user attempts to access an attribute that doesn't exist (either at all or yet). This can be useful for catching and redirecting common misspellings, giving warnings about using deprecated attributes (you can still choose to compute and return that attribute, if you wish), or deftly handing an AttributeError. It only gets called when a nonexistent attribute is accessed, however, so it isn't a true encapsulation solution. + +__setattr__(self, name, value) +Unlike __getattr__, __setattr__ is an encapsulation solution. It allows you to define behavior for assignment to an attribute regardless of whether or not that attribute exists, meaning you can define custom rules for any changes in the values of attributes. However, you have to be careful with how you use __setattr__, as the example at the end of the list will show. + +__delattr__(self, name) +This is the exact same as __setattr__, but for deleting attributes instead of setting them. The same precautions need to be taken as with __setattr__ as well in order to prevent infinite recursi + +Example: +def __setattr__(self, name, value): + self.name = value + # since every time an attribute is assigned, __setattr__() is called, this + # is recursion. +``` + ++ Example: + +```python +class Frob: + def __init__(self, bamf): + self.bamf = bamf + + def __getattr__(self, name): + return 'Frob does not have `{}` attribute.'.format(str(name)) + + +f = Frob("bamf") +f.bar +# 'Frob does not have `bar` attribute.' +f.bamf +# 'bamf' + +``` + +# Destructor + +_Destructors are called when an object gets destroyed. The __del__() method is a known as a destructor method +in Python. It is called when all references to the object have been deleted i.e when an object is garbage +collected._ + ++ Example: + +```python +def __del__(self): +# body of destructor +``` + ++ Example: + +```python +# Python program to illustrate destructor +class Employee: + + # Initializing + def __init__(self): + print('Employee created.') + + # Deleting (Calling destructor) + def __del__(self): + print('Destructor called, Employee deleted.') + + +obj = Employee() +del obj +``` + From d909c01df7c47228a66792976d78a0ad098b1e4b Mon Sep 17 00:00:00 2001 From: Andrii Date: Sat, 19 Nov 2022 21:27:51 +0200 Subject: [PATCH 2/7] adde some information about inheritance. (3. Inheritance) --- Object_Oriented_Programming/3_Inheritance.md | 304 +++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 Object_Oriented_Programming/3_Inheritance.md diff --git a/Object_Oriented_Programming/3_Inheritance.md b/Object_Oriented_Programming/3_Inheritance.md new file mode 100644 index 0000000..8f65041 --- /dev/null +++ b/Object_Oriented_Programming/3_Inheritance.md @@ -0,0 +1,304 @@ +# Inheritance + +_Inheritance is the capability of one class to derive or inherit the properties from another class._ + ++ It provides the reusability of a code. We don’t have to write the same code again and again. Also, it allows us to add + more features to a class without modifying it. + +_Inheritance allows us to define a class that inherits all the methods and properties from another class._ + +- Parent class is the class being inherited from, also called base class. +- Child class is the class that inherits from another class, also called derived class. + +### Create a Parent Class + ++ Example: + +```python +class Person: + def __init__(self, fname, lname): + self.firstname = fname + self.lastname = lname + + def printname(self): + print(self.firstname, self.lastname) + + +# Use the Person class to create an object, and then execute the printname method: + +x = Person("John", "Doe") +x.printname() +``` + +### Create a Child Class + +_Python also has a super() function that will make the child class inherit all the methods and properties from its +parent:_ + ++ Example: + +```python +class Student(Person): + def __init__(self, fname, lname): + super().__init__(fname, lname) +``` + +# Types of Inheritance in Python + +### Single Inheritance + +_In python single inheritance, a derived class is derived only from a single parent class and allows the class to derive +behaviour and properties from a single base class. This enables code re usability of a parent class, and adding new +features to a class makes code more readable, elegant and less redundant._ + ++ Example: + +```python + +class Person: + def __init__(self, fname, lname): + self.firstname = fname + self.lastname = lname + + def printname(self): + print(self.firstname, self.lastname) + + +class Student(Person): + def __init__(self, fname, lname): + super().__init__(fname, lname) + + +x = Student("John", "Doe") +x.printname() + +``` + +### Multiple Inheritance + +_When a class is derived from more than one base class it is called multiple Inheritance. The derived class inherits all +the features of the base case._ + ++ Example: + +```python +class Person: + def __init__(self, fname, lname): + self.firstname = fname + self.lastname = lname + + def printname(self): + print(self.firstname, self.lastname) + + +class Student(): + def __init__(self, fname, lname): + self.firstname = fname + self.lastname = lname + + def studing(self): + print(f"{self.fname} studing") + + +class Child(Student, Person): + def __init__(self, fname, lname): + super().__init__(fname, lname) + + +x = Child("John", "Doe") +x.printname() +x.studing() +``` + +### Multilevel Inheritance + +_In python, Multilevel inheritance is one type of inheritance being used to inherit both base class and derived +class features to the newly derived class when we inherit a derived class from a base class and another derived +class from the previous derived class up to any extent of depth of classes in python is called multilevel inheritance._ + ++ Example: + +```python +class Person: + def __init__(self, fname, lname): + self.firstname = fname + self.lastname = lname + + def printname(self): + print(self.firstname, self.lastname) + + +class Student(Person): + def __init__(self, fname, lname): + super().__init__(fname, lname) + + def studing(self): + print(f"{self.fname} studing") + + +class Child(Student): + def __init__(self, fname, lname): + super().__init__(fname, lname) + + +x = Child("John", "Doe") +x.printname() +x.studing() +``` + +### Hierarchical Inheritance + +_Hierarchical Inheritance If multiple derived classes are created from the same base, this kind of Inheritance +is known as hierarchical inheritance. In this instance, we have two base classes as a parent (base) class as well +as two children (derived) classes._ + ++ Example: + +```python +# Base class +class Parent: + def func1(self): + print("This function is in parent class.") + + +# Derived class1 + + +class Child1(Parent): + def func2(self): + print("This function is in child 1.") + + +# Derivied class2 + + +class Child2(Parent): + def func3(self): + print("This function is in child 2.") + +``` + +### Hybrid Inheritance + +_Hybrid Inheritance is a blend of more than one type of inheritance. The class is derived from the two classes +as in the multiple inheritance. However, one of the parent classes is not the base class. It is a derived class. +This feature enables the user to utilize the feature of inheritance at its best._ + ++ Example: + +```python +class Vehicle: + def vehicle_info(self): + print("Inside Vehicle class") + + +class Car(Vehicle): + def car_info(self): + print("Inside Car class") + + +class Truck(Vehicle): + def truck_info(self): + print("Inside Truck class") + + +# Sports Car can inherits properties of Vehicle and Car +class SportsCar(Car, Vehicle): + def sports_car_info(self): + print("Inside SportsCar class") + +``` + +# Method Resolution Order + +_MRO is a concept used in inheritance. It is the order in which a method is searched for in a classes hierarchy_ + ++ Example 1: + +```python +class A: + def method(self): + print("A.method() called") + + +class B: + pass + + +class C(B, A): + pass + + +c = C() +c.method() +``` + +_The MRO for this case is: C -> B -> A_ + ++ Example 2: + +```python +class A: + def method(self): + print("A.method() called") + + +class B: + def method(self): + print("B.method() called") + + +class C(A, B): + pass + + +class D(C, B): + pass + + +d = D() +d.method() +``` + +_The MRO for this case is: D -> C -> A -> B_ + +### Diamont problem* + +_The diamond problem occurs when two classes have a common parent class, and another class has both those classes as + +base classes._ + ++ Example: + +```python + + +class Class1: + + def m(self): + print("In Class1") + + +class Class2(Class1): + + def m(self): + print("In Class2") + + +class Class3(Class1): + + def m(self): + print("In Class3") + + +class Class4(Class2, Class3): + pass + + +obj = Class4() + +obj.m() + +# Class4->Class2->Class3->Class1 + +``` From 88b336d31c75729d23cbcec0bb06ce584579cfb6 Mon Sep 17 00:00:00 2001 From: Andrii Date: Sat, 19 Nov 2022 21:34:32 +0200 Subject: [PATCH 3/7] added some information about Polymorfism --- Object_Oriented_Programming/4_Polymorphism.md | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 Object_Oriented_Programming/4_Polymorphism.md diff --git a/Object_Oriented_Programming/4_Polymorphism.md b/Object_Oriented_Programming/4_Polymorphism.md new file mode 100644 index 0000000..c0dcd1e --- /dev/null +++ b/Object_Oriented_Programming/4_Polymorphism.md @@ -0,0 +1,159 @@ +# Definition + +_Polymorphism refers to having multiple forms. Polymorphism is a programming term that refers to the use of +the same function name, but with different signatures, for multiple types._ + +_Example of polymorphic functions with len()_ ++ Example: +```python +print(len("hello world")) +print(len(["Python", "Java", "C++"])) +print(len({"Name": "Tonny", "Address": "Ukrain"})) +``` + +_Below is an example of how Python can use different types of classes in the same way. +For loops that iterate through multiple objects are created. Next, call the methods without caring about +what class each object belongs to. These methods are assumed to exist in every class._ ++ Example: +```python +class Nican(): + def clas(self): + print("S-class") + + def year(self): + print("2020") + + def type(self): + print("Cabriolet") + + +class BMW(): + def clas(self): + print("A-class") + + def year(self): + print("2018") + + def type(self): + print("Sedan") + + +obj_ind = Nican() +obj_usa = BMW() +for car in (obj_ind, obj_usa): + car.clas() + car.year() + car.type() +``` + +# Overloading vs Overriding + +### Overloading + +_Method Overloading in Python is a type of Compile-time Polymorphism using which we can define two or more methods +in the same class with the same name but with a different parameter list._ ++ Example: +```python +class OverloadingExample: + def add(self, x=None, y=None): + if x != None and y != None: + return x + y + elif x != None: + return x + else: + return 0 + + +obj = OverloadingExample() + +print("Value:", obj.add()) +print("Value:", obj.add(4)) +print("Value:", obj.add(10, 20)) +``` + +### Overriding + +_Method Overriding is a type of Run-time Polymorphism. A child class method overrides (or provides its implementation) +the parent class method of the same name, parameters, and return type. It is used to over-write (redefine) a parent +class method in the derived class._ ++ Example: +```python + +class A: + + def fun1(self): + print('feature_1 of class A') + + def fun2(self): + print('feature_2 of class A') + + +class B(A): + + # Modified function that is + # already exist in class A + def fun1(self): + print('Modified feature_1 of class A by class B') + + def fun3(self): + print('feature_3 of class B') + + +# Create instance +obj = B() + +# Call the override function +obj.fun1() +``` + +| Method Overloading | Method Overriding | +|---------------------------------|---------------------------------------------------------------------------------------------| +| In the method overloading, methods or functions must have the same name and different signatures. | In the method overriding, methods or functions must have the same name and same signatures. | +|Method overloading is performed between methods within the class| Method overriding is done between parent class and child class methods. | +|It is a type of Compile-time Polymorphism| IIt is a type of Run-time Polymorphism | +|It occurs in the same class| It occurs in two classes via inheritance| +|Python does not support method overloading|Python supports method overriding| + +# + +_Polymorphism, a child class method is allowed to have the same name as the class methods in the parent class. +In inheritance, the methods belonging to the parent class are passed down to the child class. It's also possible to +change a method +that a child class has inherited from its parent._ + +_This is typically used whenever a parent class inherited method is not appropriate for the child class. +To rectify this situation, we use Method Overriding, which enables re-implementing of a method in a child class._ ++ Example: +```python + +class Helicopter: + def intro(self): + print("There are many types of helicopters.") + + def flight(self): + print("Helicopter can fly") + + +class Plane(Helicopter): + def flight(self): + print("Plane can fly.") + + +class car(Helicopter): + def flight(self): + print("car cannot fly.") + + +obj_Helicopter = Helicopter() +obj_Plane = Plane() +obj_car = car() + +obj_Helicopter.intro() +obj_Helicopter.flight() + +obj_Plane.intro() +obj_Plane.flight() + +obj_car.intro() +obj_car.flight() +``` \ No newline at end of file From 7b27239fea15b1448010bbbe0b19e277071334ff Mon Sep 17 00:00:00 2001 From: Andrii Date: Mon, 28 Nov 2022 15:29:40 +0200 Subject: [PATCH 4/7] Added some information about encapsulation but there is a problem with (name margling) --- .../5_Encapsulation.md | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 Object_Oriented_Programming/5_Encapsulation.md diff --git a/Object_Oriented_Programming/5_Encapsulation.md b/Object_Oriented_Programming/5_Encapsulation.md new file mode 100644 index 0000000..847e9d5 --- /dev/null +++ b/Object_Oriented_Programming/5_Encapsulation.md @@ -0,0 +1,208 @@ +# Encapsulation + +_Encapsulation is a technique for combining the code acting on the data (methods) +and the data itself (variables) into a single entity. Encapsulation means that a class's +variables are kept private from other classes and are only accessible through its own methods._ + +# Public, Protected, Private + +### Public + +_Public (generally methods declared in a class) are accessible from outside the class._ + +_*All members in a Python class are public by default. Any member can be accessed from outside the class environment._ + ++ Example: + +```python +class Student: + schoolName = 'School' # public class attribute + + def __init__(self, name, age): + self.name = name # public instance attribute + self.age = age # public instance attribute +``` + +### Protected + +_A class's protected members can be accessed from inside the class and by its subclasses as well. Access to any other +environment is not allowed._ + +# Показать что нельзя достучаться до protected извне класса + ++ Example: + +```python + +class Student: + _schoolName = 'Hogwarts' # protected class attribute + + def __init__(self, name, age): + self._name = name # protected instance attribute + self._age = age # protected instance attribute + + +exp1 = Student("Tony", 19) +exp1._schoolName + + +class a(Student): + def __init__(self, name, age): + super().__init__(name, age) + + +x = Student("Oleg", 11) +x._schoolName +``` + +### Private + +_The double underscore __ prefixed to a variable makes it private. It gives a strong suggestion not to touch it from +outside the class. Any attempt to do so will result in an AttributeError:_ + ++ Example: + +```python +class Student: + __schoolName = 'Hogwarts' # protected class attribute + + def __init__(self, name, age): + self._name = name # protected instance attribute + self._age = age # protected instance attribute + + +exp1 = Student("Tony", 19) +exp1._ + + +class a(Student): + def __init__(self, name, age): + super().__init__(name, age) + + +x = Student("Oleg", 11) +x.__schoolName # <----- EROR!!!! +``` + +# Getter and Setter Methods without Decorators + +### Getter and Setter + +_In object-oriented programming (OOPS), the methods known as getters are used to access +a class's private attributes. The Python getattr() function is equivalent to the setattr() function. +It changes the values of an object's attributes._ + +_In object-oriented programming (OOPS), the methods known as getters are used to access a class's secret +attributes. The Python getattr() method is equivalent to the setattr() function. It changes the values of +an object's attributes._ + ++ Example: + +```python + +class Example: + def __init__(self, age=0): + self._age = age + + # using the getter method + def get_age(self): + return self._age + # using the setter method + + def set_age(self, a): + self._age = a + + +Tony = Example() + +# using the setter function +Tony.set_age(19) + +# using the getter function +print(Tony.get_age()) + +print(Tony._age) + +``` + +# Property + +_The Python property() method has a built-in decorator called @property. When defining properties in a class, +it is used to grant "special" capability to specific methods so they can act as getters, setters, or deleters._ + ++ Example: + +```python +class Celsius: + def __init__(self, temperature=0): + self.temperature = temperature + + def to_kelvins(self): + return self.temperature + 273, 15 + + +# Create a new object +exl = Celsius() + +# Set the temperature +exl.temperature = 37 + +# Get the temperature attribute +print(exl.temperature) + +# Get the to_kelvins method +print(exl.to_kelvins()) +``` + +_The built-in Python function property() generates and returns a property object. This function's syntax is as follows:_ + +```python +property(fget=None, fset=None, fdel=None, doc=None) +``` + ++ fget is a function that retrieves an attribute's value. ++ fset is a function that sets an attribute's value. ++ fdel is capable of deleting the attribute. ++ doc is the string (like a comment) + +_Even the terms get temperature and set temperature cannot be defined since they are superfluous and contaminate the +class namespace._ + +_For this, while defining our getter and setter methods, we reuse the temperature name. Let's see how a decorator may +put this into practice:_ + ++ Example: + +```python +# Using @property decorator +class Celsius: + def __init__(self, temperature=0): + self.temperature = temperature + + def to_kelvins(self): + return (self.temperature * 1.8) + 32 + + @property + def temperature(self): + print("Getting value...") + return self._temperature + + @temperature.setter + def temperature(self, value): + print("Setting value...") + if value < -273.15: + raise ValueError("Temperature below -273 is not possible") + self._temperature = value + + +# create an object +exl = Celsius(37) + +print(exl.temperature) + +print(exl.to_kelvins()) + +coldest_thing = Celsius(-300) +``` + +# problems : Name Mangling ????? From 0dec54c598ef81f20a22151d696a993297ef7655 Mon Sep 17 00:00:00 2001 From: Andrii Date: Mon, 28 Nov 2022 15:34:04 +0200 Subject: [PATCH 5/7] Added some information about abstraction but there are many things that I don understand and can to describe --- Object_Oriented_Programming/6_Abstraction.md | 167 +++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 Object_Oriented_Programming/6_Abstraction.md diff --git a/Object_Oriented_Programming/6_Abstraction.md b/Object_Oriented_Programming/6_Abstraction.md new file mode 100644 index 0000000..84d9e8c --- /dev/null +++ b/Object_Oriented_Programming/6_Abstraction.md @@ -0,0 +1,167 @@ +# Abstraction(Abstract Classes, Abstract Methods) + +_An abstract class is a class, you cannot directly construct objects from it. +Its goal is to specify the characteristics of other classes, such as the methods and attributes +that should be included in them._ + +### Why Use Abstract Base Classes? + +_Since they lack the method implementation, abstract classes—as we have already discussed—are +used to design the framework for our classes. This is a very helpful feature, especially when child +classes need to offer their own unique implementation._ + +_To define an abstract class, you use the abc (abstract base class) module._ + +_The abc module provides you with the infrastructure for defining abstract base classes._ + +_To define an abstract method, you use the @abstractmethod decorator_ + ++ Example: + +```python +from abc import ABC, abstractmethod + + +class AbstractClass(ABC): + @abstractmethod + def abstract_method(self): + + Pass +``` + +_Say that we wish to draw several shapes. To do this, we develop a fundamental abstract class called Shape, +which will serve as the guide for subsequent forms. This class will offer the methods that must be used by +its child classes to implement particular shapes._ + ++ Example: + +```python +from abc import ABC, abstractmethod + + +class Shape(ABC): + def __init__(self, shape): + self.shape = shape + + @abstractmethod + def draw(self): + pass +``` + +_As you may have noticed, we have declared the method draw() to be undefined. +The other classes that inherit from this class will implement this method._ + +_We create classes Circle and Triangle, which will implement the draw() method and inherit the Shape class._ + ++ Example: + +```python +from abc import ABC, abstractmethod + + +class Shape(ABC): + def __init__(self, shape): + self.shape = shape + + @abstractmethod + def draw(self): + pass + + +class Circle(Shape): + def __init__(self): + super().__init__("circle") + + def draw(self): + print("Drawing a Circle") + + +class Triangle(Shape): + + def __init__(self): + super().__init__("triangle") + + def draw(self): + print("Drawing a Triangle") + + +# create a circle object +circle = Circle() +circle.draw() + +# create a triangle object +triangle = Triangle() +triangle.draw() +``` + +# Difference between abstract class and interface + +| Interface | Abstract class | +|---------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| There can only be abstract methods on an interface. Since Java 8, it is also capable of having static and default methods. | Both abstract and non-abstract methods can be found in abstract classes. | +| Multiple inheritance is supported via interface. | Multiple inheritance is not supported by abstract classes. | +| The interface class comes with its own fields and logic | The abstract class is just a template | + +# Abstract Methods + +_A method that is declared but lacks an implementation is said to be abstract. Subclasses are required to provide +implementations for the abstract methods since abstract classes cannot be instantiated._ + +### @abstractmethod, @abstractproperty + +_A decorator indicating abstract methods._ + +_As seen in the following instances of usage, abstractmethod() should be used as the innermost decorator when combined +with other method descriptors:_ + +_Python uses getters and setters in the form of properties. To utilize abstract properties, use the @abstractproperty +decorator in the ABC module._ + ++ Example: + +```python +class Example(ABC): + @abstractmethod + def abstract_method(self, arg1): + ... + + @classmethod + @abstractmethod + def abstract_classmethod(cls, arg2): + ... + + @staticmethod + @abstractmethod + def abstract_staticmethod(arg3): + ... + + @property + @abstractmethod + def abstract_property(self): + ... + + @abstractmethod + def _get_x(self): + ... + + @abstractmethod + def _set_x(self, val): + ... + + x = property(_get_x, _set_x) +``` + +# Protocol + +_Similar to Go, this capability enables you to create interfaces and verify that objects fulfill them implicitly. +This is what is known as static duck typing._ + +```python + +``` + +# Problems: + +3. Abstract Instances / Invoke Methods from Abstract Class + 4. Implementation through Subclassing + 5. Protocol and Duck Typing \ No newline at end of file From 05c694434502846e6ab202d8427f71aea8cf6d04 Mon Sep 17 00:00:00 2001 From: elusiivee Date: Mon, 5 Dec 2022 13:14:47 +0100 Subject: [PATCH 6/7] added --- Object_Oriented_Programming/6_Abstraction.md | 61 +++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/Object_Oriented_Programming/6_Abstraction.md b/Object_Oriented_Programming/6_Abstraction.md index 84d9e8c..e8e387e 100644 --- a/Object_Oriented_Programming/6_Abstraction.md +++ b/Object_Oriented_Programming/6_Abstraction.md @@ -25,7 +25,6 @@ from abc import ABC, abstractmethod class AbstractClass(ABC): @abstractmethod def abstract_method(self): - Pass ``` @@ -96,11 +95,11 @@ triangle.draw() # Difference between abstract class and interface -| Interface | Abstract class | -|---------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| Interface | Abstract class | +|----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| | There can only be abstract methods on an interface. Since Java 8, it is also capable of having static and default methods. | Both abstract and non-abstract methods can be found in abstract classes. | -| Multiple inheritance is supported via interface. | Multiple inheritance is not supported by abstract classes. | -| The interface class comes with its own fields and logic | The abstract class is just a template | +| Multiple inheritance is supported via interface. | Multiple inheritance is not supported by abstract classes. | +| The interface class comes with its own fields and logic | The abstract class is just a template | # Abstract Methods @@ -157,11 +156,57 @@ _Similar to Go, this capability enables you to create interfaces and verify that This is what is known as static duck typing._ ```python +def foo1(): + print("foo1") + + +def foo2(): + print("foo2") + + +d = {"foo1": foo1, + "foo2": foo2 + } + +d["foo1"]() # foo1 +d["foo2"]() # foo2 +``` + +# Implementation through Subclassing + +_As the name suggests, a subclass (or derived class) extends the base class; you use the parent class as a template and +add additional information to create a new template._ + +_Directly deriving from the base allows us to avoid explicitly registering the class.In this instance, +PluginImplementation is identified as implementing the abstract PluginBase using the Python class management._ + +```python +class SuperHero(): # superclass, inherits from default object + def getName(self): + raise NotImplementedError # you want to override this on the child classes + + +class SuperMan(SuperHero): # subclass, inherits from SuperHero + def getName(self): + return "Clark Kent" + +class SuperManII(SuperHero): # another subclass + def getName(self): + return "Clark Kent, Jr." + + +sm = SuperMan() +print(sm.getName()) +sm2 = SuperManII() +print(sm2.getName()) ``` +_Additionally, you may create as many subclasses as you like by reusing the parent class_ + + # Problems: -3. Abstract Instances / Invoke Methods from Abstract Class - 4. Implementation through Subclassing - 5. Protocol and Duck Typing \ No newline at end of file +Abstract Instances / Invoke Methods from Abstract Class + +there is no such thing in python, so what I have to describe \ No newline at end of file From 7a5c2204ba0b20c338bf31e4e9b8d7350a6f0e86 Mon Sep 17 00:00:00 2001 From: elusiivee Date: Wed, 7 Dec 2022 20:50:16 +0100 Subject: [PATCH 7/7] added some information about Mixin --- Object_Oriented_Programming/10_Mixin.md | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Object_Oriented_Programming/10_Mixin.md diff --git a/Object_Oriented_Programming/10_Mixin.md b/Object_Oriented_Programming/10_Mixin.md new file mode 100644 index 0000000..62c26b7 --- /dev/null +++ b/Object_Oriented_Programming/10_Mixin.md @@ -0,0 +1,49 @@ +# Mixin + +_A class that offers method implementations for reuse by several connected child classes is +known as a mixin. The inheritance does not, however, establish a connection._ + +_A mixin collects a group of techniques for reuse. Each mixin should implement a single +distinct behavior using techniques that are closely related._ + +_Mixin classes should be named with the suffix Mixin because Python does not specify a formal way to define them._ + ++ Example: + +```python +class Graphic: + def __init__(self, pos_x, pos_y, size_x, size_y): + self.pos_x = pos_x + self.pos_y = pos_y + self.size_x = size_x + self.size_y = size_y + + +class Mixin: + def resize(self, size_x, size_y): + self.size_x = size_x + self.size_y = size_y + + +class ResizableClass(Mixin, Graphic): + pass + + +rge = ResizableGraphicalEntity(6, 2, 20, 30) +rge.resize(200, 300) +``` + +_Here, the class Mixin derives straight from object rather than Graphic, +therefore ResizableClass just receives the resize function from it._ + +_As we previously stated, this makes the ResizableClass +inheritance tree simpler and lowers the danger of the diamond problem._ + +_It frees us from having to inherit undesirable methods when using Graphic +as a parent for other types._ + +_Tips:_ + ++ Simple class modifications are added using mixin classes. ++ Python uses multiple inheritance to implement mixins, which have a powerful expressive capacity but call for careful + design. \ No newline at end of file