Object-oriented programming Concept
Python is an object-oriented programming language, and we have already implemented several object-oriented ideas. The concept of an item is crucial. An object comprises two parts: data and functions (called methods) that interact with it. Strings, for example, are objects in Python. The characters that make up the string are the data of the string object. Lower, replace, and the split are some ways. Everything in Python is an object. Not just strings and lists, but also integers, floats, and even functions themselves fall into this category. Let’s now talk about Python Class and Objects.
Python Class and Objects
Classes offer a method of grouping data and functionality together. When you create a new class, you generate a new object that allows you to create new instances of that kind. All class instances may have attributes connected to them for preserving their state. Class instances may additionally have methods (specified by their class) for changing their form.
Python classes provide all the typical characteristics of Object-Oriented Programming: the class inheritance process supports multiple base classes. A derived class may override any methods of its base class or classes, and a method can call a method of a base class with the same name. Objects may hold any quantity and data. We can generate classes during runtime and change them further
Objects have different identities, and the same item may have several names in different situations, known as aliasing. While dealing with immutable basic types like strings and tuples, we can safely forget and ignore the aliasing in python. Aliasing has an unexpected impact on the semantics of Python programs using mutable objects such as lists, dictionaries, and most other kinds. The behavior of aliases is like pointers which prove to be advantageous for the program.
Python scopes and namespaces
Namespace: Python Class and Objects
A namespace is a mapping that connects names to objects. Namespaces include the collection of built-in names (including functions like abs() and built-in exception names), the global names in a module, and the local names in a function invocation. In specific ways, an object’s collection of attributes is likewise a namespace. The essential thing to understand about namespaces is that there is no relationship between names in separate namespaces; for example, two distinct modules may define the function maximize without confusion. Users of the modules must prefix it with the module’s name.
By the way, we use the term attribute for any name that follows a dot — for example, a reel is an attribute of the object a in the phrase a.reel. Referencing names in modules strictly is an attribute reference: in the phrase modname.funcname, modname is a module object, and funcname is an attribute. There is a simple mapping between the module’s attributes and the global names specified in the module: they are in the same namespace.
Attributes may be customizable or read-only. Assignment to attributes is feasible in the latter situation. Modifications to module attributes are possible: You may also use the del command to delete readable attributes.
The lifespan and creation time of each namespace is different. When the python interpreter starts, it creates namespaces containing built-in names and can’t delete them. When we read the definition of a module, it creates a global namespace; module namespaces remain until the interpreter exits.
When we call the function, it creates a global namespace; when the interpreter cannot handle the function type or throws an error, then it deletes the namespace.
Scope: Python Class and Objects
A scope is a textual area in a Python program where a namespace is immediately accessible. “Directly accessible” here indicates that a complete reference to a name tries to locate the name in the namespace.
All references and assignments are directed to the module’s global names in the middle scope if a name is declared global. To rebind variables discovered outside of the innermost scope, it may use the nonlocal statement; if not marked nonlocal, those variables are read-only.
Typically, the local scope refers to the (textually) current function’s local names. Outside of functions, the local scope refers to the same namespace as the global scope: the module’s namespace. Class declarations add a new namespace to the local scope.
It is critical to understand that scopes are decided textually: the global scope of a function declared in a module is that module’s namespace, regardless of where or by what alias the function is called. The actual search for names, on the other hand, is done dynamically, at run time — but the language definition is moving towards static name resolution at “compile” time, so don’t depend on dynamic name resolution! (In reality, local variables are already statically specified.)
Python has a peculiar feature in that assignment to names always fall into the innermost scope if no global or nonlocal statement is in place. Assignments do not transfer data; they associate names with objects. The same is true for deletions: the statement del x removes x from the namespace specified by the local scope. All actions that introduce new names make use of the local scope: import statements and function declarations, in particular, bind the module or function name in the local scope.
Example of Scope in Python
It is an example of how to refer to the various scopes and namespaces and how global and nonlocal influence variables binding.
def scope_test(): def do_local(): name = "local name" def do_nonlocal(): nonlocal name name = "nonlocal name" def do_global(): global name name = "global name" name = "test name" do_local() print("After local assignment:", name) do_nonlocal() print("After nonlocal assignment:", name) do_global() print("After global assignment:", name) scope_test() print("In global scope:", name)
After local assignment: test name After nonlocal assignment: nonlocal name After global assignment: nonlocal name In global scope: global name
The local assignment is the default, did not affect the binding of the name in the scope test. The nonlocal assignment altered the binding of the name in the scope test, whereas the global assignment altered the module-level binding.
It’s also worth noting that there was no previous binding for the name before the global assignment.
Creating Classes in Python
A class is a kind of object template. It includes the code for all the object’s methods. A simple illustration Here is a basic illustration of what a class looks like. It accomplishes nothing noteworthy.
class Example: def __init__(self, a, b): self.a = a self.b = b def add(self): return self.a + self.b e = Example(8, 6) print(e.add())
We use the Class statement to create a class. Class names typically begin with a capital letter; most classes will have a __init__ method. The underscores imply it is a unique technique. It is called a constructor. When someone creates a new object from your class, the __init__() method is invoked automatically called the constructor. Constructors often do the initialization of variables. The constructor in the above program accepts two values, a and b, and assigns them to the class variables a and b.
Every method in your class takes a particular variable named self as its first parameter. When mentioning variables or methods of your class, it must be followed by self. Self must follow the variables and methods of a class. Self aims to differentiate your class’ variables and methods from the rest of the program’s variables and functions.
- To build a new object from a class, call the constructor with the class name and any data you wish to provide. It’s most common to assign it to a variable name. The line e=Example(8,6) does this.
- Use the dot operator to access the object’s methods, as in e.add().
In object-oriented programming, inheritance is a concept that enables you to create a class that extends another class. When you do this, the newly created class inherits all of the variables and methods of the parent class is called the base class. It may then specify new variables and methods that are not available in the base class and override some of the base class’s methods. It can rewrite them to fit its own needs. Here’s an easy example:
class Basic: def __init__(self, a): self.a = a def method1(self): return self.a*2 def method2(self): return self.a+'!!!' class Derived(Basic): def __init__(self, a, b): self.a = a self.b = b def method1(self): return self.a*7 def method3(self): return self.a + self.b b = Basic('Hello') d = Derived('Hey', 'Bye') print('Basic method 1: ', b.method1()) print('Basic method 2: ', b.method2()) print() print('Derived method 1: ', d.method1()) print('Derived method 2: ', d.method2()) print('Derived method 3: ', d.method3())
Basic method 1: HelloHello Basic method 2: Hello!!! Derived method 1: HeyHeyHeyHeyHeyHeyHey Derived method 2: Hey!!! Derived method 3: HeyBye
In the above example, we can see that the Basic has overridden Derived’s method1, leading it to repeat the text seven times. The Basic has inherited Derived’s method2. Therefore it does not need to specify it. The Basic class also provides several additional features to the Derived class, including a new variable b and method, method3.
There are no “private” instance variables in Python that can only be accessed from inside an object. However, most Python code follows a convention that any word beginning with an underscore, for example, “_name” should be considered a non-public API component, whether a function, a method, or a data member. It should be seen as a possible implementation detail that may change at any moment. Python Class and Objects is a must-learn topic.
There is limited support for the method known as name mangling since there is a valid use case for class-private members to avoid name clashes between names provided by subclasses. Textually replace any identifier of the type spam (at least two leading underscores, at most one trailing underscore) with class name spam, where classname is the current class name with the leading underscore(s) deleted. This mutilation is done regardless of the identifier’s syntactic position, as long as it occurs inside the definition of a class.
Name mangling is useful for allowing subclasses override methods without interrupting intraclass method calls.
class Maps: def __init__(self, iterable): self.items_list =  self.__update(iterable) def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() method class MapsSubclass(Maps): def update(self, keys, values): # Provides new signature for update() # But does not break __init__() for item in zip(keys, values): self.items_list.append(item)
The above example would still function if MapsSubclass introduced an update identifier since it is substituted by Maps update in the Maps class and MapsSubclass update in the MapsSubclass class.
It is still possible to access or modify a private variable, but the mangling rules are mainly designed to avoid accidents. This may even be useful in certain circumstances, such as using the debugger. This may even be helpful in certain situations, such as the debugger.
Notice that code given to exec() or eval() does not regard the calling class’s classname as the current class; this is analogous to the impact of the global statement, which is also limited to code that is byte-compiled together. The same constraint applies to getattr(), setattr(), and delattr(), as well as explicitly accessing dict. Python Class and Objects is a must-learn topic, everyone should understand it clearly.
If you like this article leave a comment “Nice article!” to motivate us. Keep learning, keep coding!