Thursday, 9 November 2023

PYTHON COURSE(Beginner-100dayschallenge_code_with_Harry)

 -I am starting the tutorial by code with harry of 100 days python and i found this totally awesome.

Here is the github website (100-days-of-code-youtube/07-Day7-Exercise-1-Create-a-Calculator/main.py at a01d319a39968a36d8b40d41494aa7efb237d0d4 · CodeWithHarry/100-days-of-code-youtube) content of code with harry for 100 days course for begineer level.

-I had taken reference from fb group for commonly used methods of LIST, SET, AND DICTIONARY.

           




-In Day-46 , I learned about os module. I learned how folders are created (os.mkdir("folder name") , how are they renamed(os.rename("given folder name","New name for folder"), how to make list which is present inside the folder(os.listdir("folder name"), how to find current directory location (os.getcwd()),how to change directory(os.chdir("/target directory")).

https://www.youtube.com/watch?v=dkVYSsL90Oo&list=PLu0W_9lII9agwh1XjRt242xIpHhPT2llg&index=46
here is the youtube link for more details on os module part and more content is present here 

https://github.com/CodeWithHarry/100-days-of-code-youtube/blob/a01d319a39968a36d8b40d41494aa7efb237d0d4/46-Day-46-os-Module/.tutorial/Tutorial.md

-In Day 51 python course by code with harry, I learned the use of tell(), seek(), and truncate() built-in-io module. 

               1Byte=1character

               tell() returns the value of current position.

               tell(no.) , seek(no.), and truncate(no.)

-In Day 52 python course by code with harry, I learned the use of Lambda function using syntax:

              lambda arguments: expression

             It is an anonymous function. It means it does  not has its own name.

             we can use function as argument in function using lambda function.i.e

           ex:-

                 code:-

                     def  appl(fx,value):

                              return fx(value)

                     cube=lambda x:x*x*x

                     print(appl(cube,2))                  #def  appl(cube,2), here x in cube takes 2 value.

                Another example of use of lambda in terms of function:-

                   cube=lambda x:x*x*x

                   print(cube(3))                            # print cube of 3 

-In DAY 53, I learned how to use map(), filter(), reduce() . 

SEARCH FOR IF NOT FORMAT, OS DAY 46                   

-In DAY 54, I learned about "is" and"==" difference which compares identity(exact memory location and value respectively.

                      ex:-

                            a=4

                            b=4

                            print(a is b)                   #print     True  (since a take constant which is immutable and doesnot change when b is assigned with 4)  

                            print(a==b)                   #print      True       

                       Another example in case of list:

                               a=[2,8,6]

                               b=[2,8,6]

                               print(a is b)                  #print False (since a and b has different memory location as list is mutable)

                               print(a==b)                  #print True (since a and b has same value regardless of different memory location)

-In DAY 55, I made SNAKE, GUN, WATER GAME.

-In DAY 56, I learned about what is procedural programming, OOP and its features such as Encapsulation, Polymorphism, Inheritance.

-In Day 57, I learned about how class is created and object is defined using properties and methods.

                        example:-

                      class person:

                          name="Roshan Sewa"                     #Here name, occupation are attributes for class person and info is the method for class person as well.

                          occupation="Software developer"

                          def info(self):                                #This is self argument.

                             print(f"{self.name} is a {self.occupation})

                      a=person()                                          #This is object instance.

                      a.name="Amit"                                   #This is creation of attribute for object a.

                      a.occupation="Bokapanti"                  # Same as above

                      a.info()                                                 #This is creation of method for object using self  parameter in class info method such that  respective attribute i.e self=a based attribute is passed in info method .

-In DAY 58, I learned about about Constructor for OOP in Python.

                      A constructor is a special method in a class used to create and initialize an object of a class. It returns none unlike other function.

                       Syntax for this is:-

                              def __init__(self):

                          # initializations

                      There are two types of Constructor. They are:           

                             1.Parameterized Constructor: Takes arguments along with self

                                   SYNTAX:

                                    class Details:

                                         def __init__(self, a, g):

                                              self.animal = a

                                              self.group = g

                                    obj1 = Details("Crab", "Crustaceans")

                                    print(obj1.animal, "belongs to the", obj1.group, "group.")

                                  OUTPUT: 

                                     Crab belongs to the Crustaceans group.

                              2.Default Constructor: constructor doesn't accept any arguments from the   object and has only one argument, self, in the constructor.

                                  SYNTAX:

                                          class Details:

                                               def __init__(self):

                                                    print("animal Crab belongs to Crustaceans group")

                                          obj1=Details()

                                         OUTPUT:

                                                        animal Crab belongs to Crustaceans group

 -In DAY 59, I learned about decorator function. 

                      A decorator is a function that takes another function as an argument and returns a new function that modifies the behavior of the original function. The new function is often referred to as a "decorated" function. The basic syntax for using a decorator is the following:

 

@decorator_function

def my_func:

  pass 

example:-

def greet(fx):

   def mfx(*arg,**kwargs):

      print("Good Morning")

      fx()

      print("Thanks for using this function")

      return mfx

@greet 

def add(a,b):

   print(a+b)

add(1,4)

Here, *arg takes data argument as tuple from postional argument whereas **kwargs takes as dictionary form from keyword argument.

1 and 4 for argument of add function is input into def mfx(*arg,**kwargs):but *arg takes (1,4) since it is positional argument.

Output of this code is:

Good Morning

5

Thanks for using this function

-In DAY 61, I learned about use of inheritance of OOP.

When a class derives from another class. The child class will inherit all the public and protected properties and methods from the parent class. In addition, it can have its own properties and methods,this is called as inheritance.

Python Inheritance Syntax

class BaseClass:
  Body of base class
class DerivedClass(BaseClass):
  Body of derived class

-In DAY 62, I learned about access specifier and modifier as

In the context of object-oriented programming, access specifiers and modifiers are terms often used to describe the visibility and accessibility of class members (attributes and methods) in a programming language. Different languages have different mechanisms for controlling access to class members, and Python uses a combination of naming conventions and keywords for this purpose.


### Access Specifiers:


Access specifiers define the visibility or accessibility of class members. In many languages, there are three common access specifiers:


1. **Public:** Members marked as public are accessible from outside the class. In Python, by convention, attributes and methods without a leading underscore are considered public.


    Example:

    ```python

    class MyClass:

        def public_method(self):

            print("This is a public method.")


    obj = MyClass()

    obj.public_method()  # Accessing a public method

    ```


2. **Protected:** Members marked as protected are accessible within the class and its subclasses. In Python, by convention, attributes and methods with a single leading underscore are considered protected.


    Example:

    ```python

    class MyClass:

        def __init__(self):

            self._protected_attribute = "This is a protected attribute."


    obj = MyClass()

    print(obj._protected_attribute)  # Accessing a protected attribute

    ```


3. **Private:** Members marked as private are only accessible within the class. In Python, by convention, attributes and methods with a double leading underscore are considered private.


    Example:

    ```python

    class MyClass:

        def __init__(self):

            self.__private_attribute = "This is a private attribute."


        def __private_method(self):

            print("This is a private method.")


    obj = MyClass()

    print(obj.__private_attribute)  # Accessing a private attribute raises an AttributeError

    ```


### Access Modifiers:


Access modifiers, on the other hand, are used to modify the behavior of access specifiers. They provide additional control over the visibility of class members. Common access modifiers include:


1. **Public:** Members are accessible from anywhere.


    Example:

    ```python

    class MyClass:

        def public_method(self):

            print("This is a public method.")

    ```


2. **Protected:** Members are accessible within the class and its subclasses.


    Example:

    ```python

    class MyClass:

        def __init__(self):

            self._protected_attribute = "This is a protected attribute."

    ```


3. **Private:** Members are only accessible within the class.


    Example:

    ```python

    class MyClass:

        def __init__(self):

            self.__private_attribute = "This is a private attribute."


        def __private_method(self):

            print("This is a private method.")

    ```


In Python, the use of access specifiers and modifiers relies more on conventions than strict enforcement. The single leading underscore and double leading underscore are signals to developers about the intended visibility of the member, but they can still be accessed if needed. Python emphasizes the principle of "we are all consenting adults here," trusting developers to use these conventions responsibly.


In summary, access specifiers define the visibility of class members, and access modifiers modify (controlling accessing )that visibility. The use of conventions in Python helps express intentions regarding visibility, but it's not as strict as in some other programming languages.

"CONVENTION" MEANS WIDELY ACCEPTED WAY / a set of agreed-upon practices or guidelines that developers follow when writing code. These conventions are not enforced by the programming language itself but are established by the community or organization to improve code readability, maintainability, and consistency.

-In Day 65,  I learned about Static method. 

Static methods in Python are methods that belong to a class rather than an instance of the class. They are defined using the @staticmethod decorator and do not have access to the instance of the class (i.e. self). They are called on the class itself, not on an instance of the class. Static methods are often used to create utility functions that don't need access to instance data.

class Math:
    @staticmethod
    def add(a, b):
        return a + b

result = Math.add(1, 2)
print(result) # Output: 3

In this example, the add method is a static method of the Math class. It takes two parameters a and b and returns their sum. The method can be called on the class itself, without the need to create an instance of the class.

a=Math()

print(a.add(1, 2))    #Output : 3

-In Day 66, I learned about instance variable and class variable. 

Inside constructor, instance variable is created.

class roshan:

def sewa(self):

print("Hey ")

a=roshan()

a.sewa() is equivalent to roshan.sewa(a) while accessing sewa method of class.


Class Variables

Class variables are defined at the class level and are shared among all instances of the class. They are defined outside of any method and are usually used to store information that is common to all instances of the class. For example, a class variable can be used to store the number of instances of a class that have been created.

class MyClass:
    class_variable = 0
    
    def __init__(self):
        MyClass.class_variable += 1        #Myclass keyword at initial represent that it is class variable.
        
    def print_class_variable(self):
        print(MyClass.class_variable)
        

obj1 = MyClass()
obj2 = MyClass()

obj1.print_class_variable() # Output: 2
obj2.print_class_variable() # Output: 2

In the example above, the class_variable is shared among all instances of the class MyClass. When we create new instances of MyClass, the value of class_variable is incremented. When we call the print_class_variable method on obj1 and obj2, we get the same value of class_variable.

Instance Variables

Instance variables are defined at the instance level and are unique to each instance of the class. They are defined inside the init method and are usually used to store information that is specific to each instance of the class. For example, an instance variable can be used to store the name of an employee in a class that represents an employee.

class MyClass:
    def __init__(self, name):
        self.name = name
        
    def print_name(self):
        print(self.name)

obj1 = MyClass("John")
obj2 = MyClass("Jane")

obj1.print_name() # Output: John
obj2.print_name() # Output: Jane

In the example above, each instance of the class MyClass has its own value for the name variable. When we call the print_name method on obj1 and obj2, we get different values for name.

-In day 67, I learned about class method.

Given below shows the difference between class method and instance method.

In Python, when you create a method inside a class, it becomes an instance method by default. An instance method is a method that operates on an instance of the class and has access to the instance's attributes. It takes the instance itself as the first parameter, conventionally named `self`.


If you want to create a method that operates on the class itself rather than an instance of the class, you can use the `@classmethod` decorator. A class method takes the class itself as the first parameter, conventionally named `cls`.


Here's an example to illustrate the difference between an instance method and a class method:


```python

class MyClass:

    # Instance method (default)

    def instance_method(self):

        print("This is an instance method.")


    # Class method

    @classmethod

    def class_method(cls):

        print("This is a class method.")


# Creating an instance of MyClass

obj = MyClass()


# Calling instance method

obj.instance_method()


# Calling class method

MyClass.class_method()

```


In the above example, `instance_method` is an instance method because it takes `self` as the first parameter. On the other hand, `class_method` is a class method because it takes `cls` as the first parameter and is decorated with `@classmethod'.

-In Day 70, I learned about class method used as alternative constructor.

there are times when you may want to create an object in a different way, or with different initial values, than what is provided by the default constructor. This is where class methods can be used as alternative constructors.

A class method belongs to the class rather than to an instance of the class. One common use case for class methods as alternative constructors is when you want to create an object from data that is stored in a different format, such as a string or a dictionary. For example, consider a class named "Person" that has two attributes: "name" and "age". The default constructor for the class might look like this:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

But what if you want to create a Person object from a string that contains the person's name and age, separated by a comma? You can define a class method named "from_string" to do this:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_string(cls, string):
        name, age = string.split(',')
        return cls(name, int(age))

Now you can create a Person object from a string like this:

person = Person.from_string("John Doe, 30")

Another common use case for class methods as alternative constructors is when you want to create an object with a different set of default values than what is provided by the default constructor. For example, consider a class named "Rectangle" that has two attributes: "width" and "height". The default constructor for the class might look like this:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

But what if you want to create a Rectangle object with a default width of 10 and a default height of 10? You can define a class method named "square" to do this:(This means format different case)

class Rectangle:
  def __init__(self, width, height):
    self.width = width
    self.height = height

  @classmethod
  def square(cls, size):
    return cls(size, size)

Now you can create a square rectangle like this:

rectangle = Rectangle.square(10)


-In Day 71,  I learned about dir(),  __dict__and help() methods in python.

dir(): The dir() function returns a list of all the attributes and methods (including dunder methods) available for an object. It is a useful tool for discovering what you can do with an object. Example:

>>> x = [1, 2, 3]
>>> dir(x)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']


The __dict__ attribute

__dict__: The __dict__ attribute returns a dictionary representation of an object's attributes. It is a useful tool for introspection. Example:

>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...
>>> p = Person("John", 30)
>>> p.__dict__






Output

{'name': 'John', 'age': 30}

The help() mehthod

help(): The help() function is used to get help documentation for an object, including a description of its attributes and methods.

In conclusion, dir(), dict, and help() are useful built-in functions in Python that can be used to get information about objects. They are valuable tools for introspection and discovery.

-In Day 72,  I learned about super keyword.

The super() keyword in Python is used to refer to the parent class. It is especially useful when a class inherits from multiple parent classes and you want to call a method from one of the parent classes.

When a class inherits from a parent class, it can override or extend the methods defined in the parent class. However, sometimes you might want to use the parent class method in the child class. This is where the super() keyword comes in handy.

Here's an example of how to use the super() keyword in a simple inheritance scenario:

class ParentClass:
    def parent_method(self):
        print("This is the parent method.")

class ChildClass(ParentClass):
    def child_method(self):
        print("This is the child method.")
        super().parent_method()

child_object = ChildClass()
child_object.child_method()

Output:

This is the child method.
This is the parent method.

In this example, we have a ParentClass with a parent_method and a ChildClass that inherits from ParentClass and overrides the child_method. When the child_method is called, it first prints "This is the child method." and then calls the parent_method using the super() keyword.

The super() keyword is also useful when a class inherits from multiple parent classes. In this case, you can specify the parent class from which you want to call the method.

Here's an example:

class ParentClass1:
    def parent_method(self):
        print("This is the parent method of ParentClass1.")

class ParentClass2:
    def parent_method(self):
        print("This is the parent method of ParentClass2.")

class ChildClass(ParentClass1, ParentClass2):
    def child_method(self):
        print("This is the child method.")
        super().parent_method()

child_object = ChildClass()
child_object.child_method()

Output:

This is the child method.
This is the parent method of ParentClass1.

In this example, the ChildClass inherits from both ParentClass1 and ParentClass2. The child_method calls the parent_method of the first parent class using the super() keyword.

In conclusion, the super() keyword is a useful tool in Python when you want to call a parent class method in a child class. It can be used in inheritance scenarios with a single parent class or multiple parent classes.

-In DAY 73, I learned about magic/dunder method.

Certainly! Let's delve a bit deeper into the `__repr__` and `__str__` methods in Python.


### `__str__` Method:


The `__str__` method is used to define the "informal" or "user-friendly" string representation of an object. It is called when the `str()` function is used or when you use `print(obj)`. This method is intended to provide a human-readable version of the object.


Example:


```python

class Employee:

    def __str__(self):

        return "Employee object (human-readable)"

```


When you print an instance of this class or use `str(instance)`, you will get the human-readable string representation:


```python

e = Employee()

print(e)  # Output: Employee object (human-readable)

```


### `__repr__` Method:


The `__repr__` method, on the other hand, is used to define the "formal" or "developer-friendly" string representation of an object. It is called when the `repr()` function is used, when you use backticks (deprecated), or when you inspect an object in an interactive interpreter. This method is intended to provide a more detailed and unambiguous representation of the object.


Example:


```python

class Employee:

    def __repr__(self):

        return "Employee()"

```


When you explicitly call `repr(instance)` or use backticks (deprecated), you will get the developer-friendly string representation:


```python

e = Employee()

print(repr(e))  # Output: Employee()

```


The key distinction is that `__str__` is more for end-users, providing a readable output, while `__repr__` is more for developers, offering a detailed and unambiguous representation of the object, often in a format that could be used to recreate the object.

In Python, the __call__ method is a special method that you can define in a class to make instances of that class callable. When you make an object callable, you can treat it like a function and invoke it using parentheses.

Here's a simple example:

class CallableClass: def __call__(self, *args, **kwargs): print("Object is callable!") print("Arguments:", args) print("Keyword arguments:", kwargs) # Creating an instance of the class obj = CallableClass() # Calling the instance as if it were a function obj(1, 2, key='value')

In this example, the CallableClass defines the __call__ method. When you create an instance of this class (obj), you can call it as if it were a function. The __call__ method is executed when you invoke the instance with parentheses.

When you run this code, you'll see the following output:

Object is callable! Arguments: (1, 2) Keyword arguments: {'key': 'value'}


In Python, the __len__() method is a special method that you can define in your custom classes to enable the use of the built-in len() function on instances of that class. This method should return the length of the object, and it is commonly used with data structures such as lists, strings, or other iterable objects.

Here's an example with a custom class that implements __len__():

class CustomList: def __init__(self, items): self.items = items def __len__(self): return len(self.items) # Creating an instance of the class my_list = CustomList([1, 2, 3, 4, 5]) # Using len() on the instance length = len(my_list) print("Length of the custom list:", length)

In this example, the CustomList class has a __len__ method that returns the length of the list stored in the items attribute. When you use len(my_list), it internally calls the __len__ method of the CustomList class.

You can implement __len__ in your own classes when you want instances of those classes to behave like built-in objects with respect to determining their length. For example, this is commonly done with custom container classes, allowing users of your class to use the len() function on instances of it.

-In DAY 74, I learned about method overriding.

Method overriding in Python occurs when a subclass provides a specific implementation for a method that is already defined in its superclass. This allows a subclass to provide a specialized version of a method that is already implemented in its superclass, altering or extending its behavior.

Here's a basic example:

class Animal: def make_sound(self): print("Generic animal sound") class Dog(Animal): def make_sound(self): print("Woof! Woof!") class Cat(Animal): def make_sound(self): print("Meow!") # Creating instances generic_animal = Animal() dog = Dog() cat = Cat() # Calling overridden method generic_animal.make_sound() # Output: Generic animal sound dog.make_sound() # Output: Woof! Woof! cat.make_sound() # Output: Meow!

!In this example:

  • The Animal class has a method called make_sound.
  • The Dog and Cat classes are subclasses of Animal and both override the make_sound method with their own implementations.

When you call make_sound on an instance of Dog or Cat, Python looks for the method in the subclass first. If it finds the method in the subclass, it uses that implementation; otherwise, it looks for the method in the superclass.

Key points about method overriding:

  1. The method in the subclass must have the same name and the same signature (i.e., the same parameters) as the method in the superclass.

  2. The overridden method in the subclass should provide a specialized implementation, but it can also call the overridden method in the superclass using super().

  3. class Dog(Animal): def make_sound(self): super().make_sound() # Call the superclass method print("Woof! Woof!")


Method overriding is a fundamental concept in object-oriented programming that allows for polymorphism, where different classes can be treated as instances of the same class through a common interface (in this case, the shared method name).









No comments:

Post a Comment

NEW FINDINGS IN PYTHON

 TITLE:-WE CAN UPDATE DICTIONARY BY USING LOOPING WITHOUT USING UPDATE() FUNCTION. EXAMPLE: with open('currencyData.txt') as f: li...