Recall Init Again Object Oriented Programming
i. Object Oriented Programming
By Bernd Klein. Concluding modified: 01 Feb 2022.
Though Python is an object-oriented linguistic communication without fuss or quibble, we have so far intentionally avoided the treatment of object-oriented programming (OOP) in the previous chapters of our Python tutorial. Nosotros skipped OOP, considering we are convinced that information technology is easier and more fun to start learning Python without having to know about all the details of object-oriented programming.
Even though we take avoided OOP, information technology has nevertheless ever been present in the exercises and examples of our course. We used objects and methods from classes without properly explaining their OOP background. In this chapter, we will catch upward on what has been missing so far. We will provide an introduction into the principles of object oriented programming in general and into the specifics of the OOP approach of Python. OOP is one of the most powerful tools of Python, merely nevertheless you don't have to utilise it, i.e. y'all tin write powerful and efficient programs without it as well.
Though many computer scientists and programmers consider OOP to exist a mod programming paradigm, the roots go back to 1960s. The first programming language to apply objects was Simula 67. As the name implies, Simula 67 was introduced in the yr 1967. A major breakthrough for object-oriented programming came with the programming language Smalltalk in the 1970s.
You will larn to know the four major principles of object-orientation and the way Python deals with them in the next department of this tutorial on object-oriented programming:
- Encapsulation
- Data Brainchild
- Polymorphism
- Inheritance
Earlier nosotros start the section about the way OOP is used in Python, we want to give you a general idea nearly object-oriented programming. For this purpose, we would like to draw your attention to a public library. Let'south think about a huge one, like the "British Library" in London or the "New York Public Library" in New York. If it helps, you lot can imagine the libraries in Paris, Berlin, Ottawa or Toronto* as well. Each of these contain an organized collection of books, periodicals, newspapers, audiobooks, films and then on.
Generally, in that location are two opposed ways of keeping the stock in a library. You can apply a "closed access" method that is the stock is non displayed on open shelves. In this system, trained staff brings the books and other publications to the users on demand. Another manner of running a library is open-access shelving, too known every bit "open shelves". "Open" means open to all users of the library not only peculiarly trained staff. In this case the books are openly displayed. Imperative languages like C could be seen as open-access shelving libraries. The user can do everything. Information technology's upwardly to the user to find the books and to put them back at the right shelf. Even though this is nifty for the user, it might lead to serious problems in the long run. For example some books will be misplaced, and so it's hard to observe them again. As y'all may have guessed already, "closed access" can exist compared to object oriented programming. The analogy can be seen like this: The books and other publications, which a library offers, are similar the data in an object-oriented programme. Access to the books is restricted like access to the information is restricted in OOP. Getting or returning a book is simply possible via the staff. The staff functions similar the methods in OOP, which control the access to the data. So, the data, - often called attributes, - in such a program can exist seen as beingness hidden and protected by a shell, and it can only be accessed past special functions, usually called methods in the OOP context. Putting the data behind a "shell" is called Encapsulation. So a library tin can be regarded as a class and a book is an instance or an object of this class. Generally speaking, an object is defined by a class. A class is a formal clarification of how an object is designed, i.e. which attributes and methods information technology has. These objects are called instances as well. The expressions are in most cases used synonymously. A class should not exist confused with an object.
OOP in Python
Even though we haven't talked almost classes and object orientation in previous chapters, we have worked with classes all the fourth dimension. In fact, everything is a course in Python. Guido van Rossum has designed the linguistic communication co-ordinate to the principle "showtime-class everything". He wrote: "One of my goals for Python was to make it so that all objects were "first course." By this, I meant that I wanted all objects that could be named in the language (e.1000., integers, strings, functions, classes, modules, methods, and so on) to take equal status. That is, they tin can be assigned to variables, placed in lists, stored in dictionaries, passed as arguments, and so along." (Blog, The History of Python, Feb 27, 2009) In other words, "everything" is treated the same way, everything is a class: functions and methods are values only like lists, integers or floats. Each of these are instances of their respective classes.
OUTPUT:
OUTPUT:
def f ( x ): return x + i type ( f )
OUTPUT:
OUTPUT:
One of the many integrated classes in Python is the list class, which we have quite often used in our exercises and examples. The listing form provides a wealth of methods to build lists, to access and change elements, or to remove elements:
ten = [ 3 , 6 , 9 ] y = [ 45 , "abc" ] impress ( x [ 1 ])
OUTPUT:
ten [ i ] = 99 x . append ( 42 ) last = y . pop () print ( final )
OUTPUT:
The variables x and y of the previous example denote two instances of the listing class. In simplified terms, we take said so far that "x and y are lists". Nosotros will use the terms "object" and "instance" synonymously in the following chapters, as it is often done**.
pop and append of the previous instance are methods of the listing class. pop returns the top (or you might think of information technology as the "rightest") chemical element of the list and removes this chemical element from the list. We volition not explain how Python has implemented lists internally. We don't need this information, because the listing course provides united states of america with all the necessary methods to access the data indirectly. That is, the encapsulation details are encapsulated. Nosotros will larn nearly encapsulation later on.
A Minimal Course in Python
We will blueprint and apply a robot grade in Python as an case to demonstrate the almost important terms and ideas of object orientation. Nosotros will start with the simplest class in Python.
class Robot: pass
Nosotros can realize the central syntactical structure of a class in Python: A grade consists of two parts: the header and the body. The header usually consists of simply one line of lawmaking. It begins with the keyword "class" followed by a blank and an arbitrary name for the form. The class name is "Robot" in our case. The grade proper name is followed past a listing of other class names, which are classes from which the defined grade inherits. These classes are called superclasses, base classes or sometimes parent classes. If you look at our example, you volition see that this listing of superclasses is non obligatory. You lot don't have to bother about inheritance and superclasses for now. We will introduce them later.
The body of a course consists of an indented block of statements. In our instance a single argument, the "pass" statement.
A course object is created, when the definition is left normally, i.due east. via the end. This is basically a wrapper around the contents of the namespace created past the grade definition.
It's difficult to believe, especially for C++ or Java programmers, just we have already defined a complete class with only three words and two lines of code. We are capable of using this class also:
class Robot : pass if __name__ == "__main__" : 10 = Robot () y = Robot () y2 = y print ( y == y2 ) print ( y == x )
OUTPUT:
We accept created two different robots x and y in our example. Besides this, we accept created a reference y2 to y, i.eastward. y2 is an alias name for y.
Attributes
Those who have learned already another object-oriented language, must take realized that the terms attributes and properties are usually used synonymously. It may even be used in the definition of an attribute, like Wikipedia does: "In computing, an attribute is a specification that defines a property of an object, element, or file. Information technology may also refer to or set the specific value for a given instance of such."
Even in normal English usage the words "attribute" and "holding" can exist used in some cases as synonyms. Both can have the pregnant "An attribute, feature, quality, or characteristic of something or someone". Usually an "aspect" is used to denote a specific ability or feature which something or someone has, like black pilus, no pilus, or a quick perception, or "her quickness to grasp new tasks". And then, think a while about your outstanding attributes. What about your "outstanding properties"? Nifty, if one of your strong points is your ability to quickly understand and adapt to new situations! Otherwise, y'all would not be learning Python!
Permit's get back to Python: We will learn later that properties and attributes are substantially unlike things in Python. This subsection of our tutorial is virtually attributes in Python. And then far our robots have no attributes. Not even a proper noun, like it is customary for ordinary robots, isn't it? So, allow'south implement a proper noun attribute. "type designation", "build year" etc. are easily conceivable as further attributes as well***.
Attributes are created inside a class definition, as we will presently learn. We can dynamically create arbitrary new attributes for existing instances of a course. Nosotros do this past joining an arbitrary proper name to the instance proper noun, separated by a dot ".". In the following case, we demonstrate this by creating an aspect for the name and the twelvemonth built:
class Robot : pass x = Robot () y = Robot () x . proper name = "Marvin" x . build_year = "1979" y . name = "Caliban" y . build_year = "1993" print ( x . name )
OUTPUT:
OUTPUT:
As we accept said before: This is not the way to properly create example attributes. We introduced this example, because we call back that it may assistance to make the post-obit explanations easier to understand.
If you want to know, what's happening internally: The instances possess dictionaries __dict__
, which they use to shop their attributes and their corresponding values:
OUTPUT:
{'name': 'Marvin', 'build_year': '1979'}
OUTPUT:
{'name': 'Caliban', 'build_year': '1993'}
Attributes can be jump to grade names likewise. In this instance, each instance will possess this proper noun as well. Watch out, what happens, if you assign the same proper noun to an instance:
class Robot ( object ): laissez passer
x = Robot () Robot . make = "Kuka" 10 . brand
OUTPUT:
10 . brand = "Thales" Robot . brand
OUTPUT:
OUTPUT:
OUTPUT:
OUTPUT:
If y'all look at the __dict__
dictionaries, yous tin see what's happening.
OUTPUT:
OUTPUT:
OUTPUT:
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Robot' objects>, '__weakref__': <attribute '__weakref__' of 'Robot' objects>, '__doc__': None, 'brand': 'Thales'})
If you effort to access y.brand, Python checks offset, if "brand" is a central of the y. __dict__
dictionary. If information technology is not, Python checks, if "brand" is a cardinal of the Robot. __dict__
. If so, the value tin can be retrieved.
If an attribute proper name is not in included in either of the dictionary, the attribute proper name is not defined. If you try to admission a not-existing attribute, you will raise an AttributeError:
OUTPUT:
--------------------------------------------------------------------------- AttributeError Traceback (most recent telephone call concluding) <ipython-input-28-82fa0f11497d> in <module> ----> 1x.energy AttributeError: 'Robot' object has no attribute 'free energy'
By using the function getattr, y'all can prevent this exception, if you provide a default value as the third argument:
getattr ( ten , 'free energy' , 100 )
OUTPUT:
Binding attributes to objects is a general concept in Python. Even function names can be attributed. You lot can bind an aspect to a function name in the same way, we have done then far to other instances of classes:
def f ( x ): return 42 f . ten = 42 print ( f . x )
OUTPUT:
This can be used as a replacement for the static function variables of C and C++, which are not possible in Python. Nosotros use a counter attribute in the following example:
def f ( 10 ): f . counter = getattr ( f , "counter" , 0 ) + 1 return "Monty Python" for i in range ( 10 ): f ( i ) print ( f . counter )
OUTPUT:
Some dubiousness may ascend at this betoken. It is possible to assign attributes to near class instances, but this has cypher to do with defining classes. Nosotros volition see soon how to assign attributes when nosotros ascertain a class.
To properly create instances of classes, we also need methods. Y'all will learn in the following subsection of our Python tutorial, how you can define methods.
Live Python grooming
Upcoming online Courses
Enrol here
Methods
Methods in Python are essentially functions in accordance with Guido's proverb "fantabulous everything".
Permit'due south define a function "hi", which takes an object "obj" as an statement and assumes that this object has an aspect "proper name". We will also define our basic Robot form again:
def how-do-you-do ( obj ): print ( "Hi, I am " + obj . proper noun + "!" ) class Robot : pass ten = Robot () x . proper noun = "Marvin" hi ( x )
OUTPUT:
Nosotros will now demark the part „hello" to a class attribute „say_hi"!
def hi ( obj ): impress ( "Howdy, I am " + obj . proper name ) form Robot : say_hi = hi x = Robot () x . name = "Marvin" Robot . say_hi ( x )
OUTPUT:
"say_hi" is called a method. Unremarkably, it will be called similar this:
x.say_hi()
It is possible to define methods similar this, simply you shouldn't do it.
The proper manner to practise it:
- Instead of defining a function outside of a class definition and binding it to a class attribute, we define a method directly inside (indented) of a form definition.
- A method is "just" a office which is defined inside a class.
- The first parameter is used a reference to the calling case.
- This parameter is ordinarily called self.
- Self corresponds to the Robot object x.
Nosotros have seen that a method differs from a function but in ii aspects:
- It belongs to a course, and information technology is defined within a class
- The showtime parameter in the definition of a method has to be a reference to the example, which called the method. This parameter is usually called "self".
Equally a matter of fact, "self" is not a Python keyword. It's just a naming convention! So C++ or Coffee programmers are complimentary to call it "this", but this way they are risking that others might have greater difficulties in understanding their code!
Well-nigh other object-oriented programming languages pass the reference to the object (self) as a hidden parameter to the methods.
You lot saw before that the calls Robot.say_hi(x)". and "ten.say_hi()" are equivalent. "x.say_hi()" can be seen as an "abbreviated" class, i.e. Python automatically binds it to the case proper noun. Besides this "x.say_hi()" is the usual manner to call methods in Python and in other object oriented languages.
For a Class C, an instance ten of C and a method m of C the following three method calls are equivalent:
- blazon(x).g(10, ...)
- C.m(x, ...)
- x.chiliad(...)
Before you continue with the following text, y'all may mull over the previous instance for awhile. Tin you figure out, what is wrong in the design?
There is more than one thing about this code, which may disturb you, but the essential problem at the moment is the fact that we create a robot and that subsequently the creation, nosotros shouldn't forget about naming information technology! If nosotros forget it, say_hi will enhance an mistake.
Nosotros need a machinery to initialize an instance right later its cosmos. This is the __init__
-method, which we encompass in the next section.
The __init__
Method
We want to define the attributes of an instance right after its cosmos. __init__
is a method which is immediately and automatically chosen after an instance has been created. This proper name is fixed and information technology is not possible to chose another proper name. __init__
is ane of the so-chosen magic methods,nosotros will get to know information technology with some more details later on. The __init__
method is used to initialize an instance. There is no explicit constructor or destructor method in Python, as they are known in C++ and Java. The __init__
method can be anywhere in a class definition, only it is usually the showtime method of a class, i.east. it follows right after the class header.
class A : def __init__ ( self ): print ( "__init__ has been executed!" ) 10 = A ()
OUTPUT:
__init__ has been executed!
We add an __init__
-method to our robot class:
class Robot : def __init__ ( cocky , proper noun = None ): cocky . name = name def say_hi ( self ): if self . name : print ( "Howdy, I am " + self . name ) else : print ( "Hi, I am a robot without a name" ) x = Robot () x . say_hi () y = Robot ( "Marvin" ) y . say_hi ()
OUTPUT:
Hullo, I am a robot without a name Hi, I am Marvin
Definitions of Terms
Data Abstraction, Information Encapsulation and Information Hiding are often synonymously used in books and tutorials on OOP. Notwithstanding, there is a difference. Encapsulation is seen as the bundling of data with the methods that operate on that data. Information hiding on the other hand is the principle that some internal data or information is "hidden", and so that information technology can't exist accidentally inverse. Data encapsulation via methods doesn't necessarily mean that the data is hidden. You might be capable of accessing and seeing the data anyway, merely using the methods is recommended. Finally, data abstraction is nowadays, if both data hiding and information encapsulation is used. In other words, information abstraction is the hypernym:
Data Abstraction = Information Encapsulation + Information Hiding
Encapsulation is often achieved by providing ii kinds of methods for attributes: The methods for retrieving or accessing the values of attributes are called getter methods. Getter methods do non modify the values of attributes, they simply render the values. The methods used for changing the values of attributes are called setter methods.
We will define now a Robot form with a Getter and a Setter for the name attribute. We will call them get_name and set_name appropriately.
class Robot : def __init__ ( self , name = None ): cocky . name = name def say_hi ( cocky ): if self . name : print ( "Howdy, I am " + self . proper name ) else : print ( "Hi, I am a robot without a name" ) def set_name ( self , name ): cocky . proper name = name def get_name ( self ): return cocky . proper noun ten = Robot () x . set_name ( "Henry" ) x . say_hi () y = Robot () y . set_name ( x . get_name ()) print ( y . get_name ())
OUTPUT:
Before you go on, you can do a trivial exercise. You tin add together an additional attribute "build_year" with Getters and Setters to the Robot course.
form Robot : def __init__ ( self , name = None , build_year = None ): self . proper name = name self . build_year = build_year def say_hi ( self ): if self . name : print ( "Hi, I am " + self . name ) else : print ( "Hi, I am a robot without a name" ) if self . build_year : impress ( "I was built in " + str ( self . build_year )) else : print ( "It's not known, when I was created!" ) def set_name ( cocky , proper noun ): self . name = name def get_name ( self ): return self . name def set_build_year ( self , past ): self . build_year = by def get_build_year ( cocky ): return self . build_year x = Robot ( "Henry" , 2008 ) y = Robot () y . set_name ( "Marvin" ) x . say_hi () y . say_hi ()
OUTPUT:
Hi, I am Henry I was congenital in 2008 Howdy, I am Marvin It's not known, when I was created!
There is still something wrong with our Robot course. The Zen of Python says: "In that location should be i-- and preferably only one --obvious fashion to do it." Our Robot class provides us with two ways to access or to change the "name" or the "build_year" attribute. This tin can be prevented by using individual attributes, which we will explicate later.
__str__
- and __repr__
-Methods
We volition have a curt break in our treatise on data abstraction for a quick side-trip. We desire to innovate ii important magic methods "__str__"
and "__repr__"
, which nosotros volition need in futurity examples. In the class of this tutorial, we have already encountered the __str__
method. We had seen that we can depict various data as cord by using the str part, which uses "magically" the internal __str__
method of the corresponding information type. __repr__
is like. It as well produces a cord representation.
l = [ "Python" , "Java" , "C++" , "Perl" ] impress ( l )
OUTPUT:
['Python', 'Java', 'C++', 'Perl']
OUTPUT:
"['Python', 'Java', 'C++', 'Perl']"
OUTPUT:
"['Python', 'Java', 'C++', 'Perl']"
d = { "a" : 3497 , "b" : 8011 , "c" : 8300 } print ( d )
OUTPUT:
{'a': 3497, 'b': 8011, 'c': 8300}
OUTPUT:
"{'a': 3497, 'b': 8011, 'c': 8300}"
OUTPUT:
"{'a': 3497, 'b': 8011, 'c': 8300}"
OUTPUT:
OUTPUT:
If you apply str or repr to an object, Python is looking for a corresponding method __str__
or __repr__
in the grade definition of the object. If the method does exist, it volition be chosen. In the post-obit example, we define a class A, having neither a __str__
nor a __repr__
method. We want to see, what happens, if nosotros use impress directly on an instance of this form, or if we apply str or repr to this instance:
class A : laissez passer a = A () impress ( a )
OUTPUT:
<__main__.A object at 0x0000016B162A2688>
OUTPUT:
<__main__.A object at 0x0000016B162A2688>
OUTPUT:
<__main__.A object at 0x0000016B162A2688>
OUTPUT:
<__main__.A at 0x16b162a2688>
Equally both methods are not available, Python uses the default output for our object "a".
If a class has a __str__
method, the method volition be used for an instance 10 of that class, if either the office str is practical to it or if it is used in a print office. __str__
volition non exist used, if repr is called, or if we effort to output the value directly in an interactive Python shell:
class A : def __str__ ( self ): return "42" a = A () impress ( repr ( a ))
OUTPUT:
<__main__.A object at 0x0000016B162A4108>
OUTPUT:
OUTPUT:
<__main__.A at 0x16b162a4108>
Otherwise, if a class has only the __repr__
method and no __str__
method, __repr__
will be practical in the situations, where __str__
would be applied, if information technology were available:
class A : def __repr__ ( self ): return "42" a = A () print ( repr ( a )) print ( str ( a )) a
OUTPUT:
A frequently asked question is when to apply __repr__
and when __str__
. __str__
is always the right selection, if the output should be for the end user or in other words, if information technology should be nicely printed. __repr__
on the other hand is used for the internal representation of an object. The output of __repr__
should exist - if viable - a string which tin be parsed by the python interpreter. The outcome of this parsing is in an equal object. That is, the following should be truthful for an object "o":
o == eval(repr(o))
This is shown in the following interactive Python session:
l = [ 3 , 8 , 9 ] due south = repr ( fifty ) southward
OUTPUT:
OUTPUT:
OUTPUT:
We show in the following example with the datetime module that eval can only be applied on the strings created past repr:
import datetime today = datetime . datetime . at present () str_s = str ( today ) eval ( str_s )
OUTPUT:
Traceback (most recent call last): File "C:\Users\melis\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3326, in run_code exec(code_obj, cocky.user_global_ns, self.user_ns) File "<ipython-input-57-52b036e82a64>" , line four , in <module> eval(str_s) File "<cord>" , line 1 2020-06-11 17:48:26.391635 ^ SyntaxError : invalid token
repr_s = repr ( today ) t = eval ( repr_s ) blazon ( t )
OUTPUT:
We tin can run into that eval(repr_s) returns again a datetime.datetime object. The cord created by str can't be turned into a datetime.datetime object by parsing information technology.
We will extend our robot form with a repr method. We dropped the other methods to continue this example simple:
class Robot : def __init__ ( self , name , build_year ): self . name = proper noun self . build_year = build_year def __repr__ ( cocky ): render "Robot('" + cocky . name + "', " + str ( self . build_year ) + ")" if __name__ == "__main__" : x = Robot ( "Marvin" , 1979 ) x_str = str ( x ) print ( x_str ) print ( "Type of x_str: " , blazon ( x_str )) new = eval ( x_str ) print ( new ) impress ( "Blazon of new:" , type ( new ))
OUTPUT:
Robot('Marvin', 1979) Type of x_str: <class 'str'> Robot('Marvin', 1979) Type of new: <grade '__main__.Robot'>
x_str has the value Robot('Marvin', 1979). eval(x_str) converts it once more into a Robot instance.
Now it's time to extend our form with a user friendly __str__
method:
grade Robot : def __init__ ( self , proper noun , build_year ): self . name = proper name self . build_year = build_year def __repr__ ( self ): return "Robot('" + self . name + "', " + str ( self . build_year ) + ")" def __str__ ( self ): return "Name: " + cocky . name + ", Build Yr: " + str ( self . build_year ) if __name__ == "__main__" : x = Robot ( "Marvin" , 1979 ) x_str = str ( 10 ) print ( x_str ) print ( "Type of x_str: " , type ( x_str )) new = eval ( x_str ) print ( new ) print ( "Blazon of new:" , type ( new ))
OUTPUT:
Name: Marvin, Build Year: 1979 Type of x_str: <class 'str'>
When we commencement this program, we can see that it is not possible to convert our string x_str, created via str(x), into a Robot object anymore.
We show in the following program that x_repr can still be turned into a Robot object:
form Robot : def __init__ ( self , name , build_year ): cocky . proper noun = name self . build_year = build_year def __repr__ ( cocky ): render "Robot( \" " + self . name + " \" ," + str ( cocky . build_year ) + ")" def __str__ ( cocky ): return "Proper name: " + cocky . name + ", Build Year: " + str ( self . build_year ) if __name__ == "__main__" : 10 = Robot ( "Marvin" , 1979 ) x_repr = repr ( ten ) print ( x_repr , blazon ( x_repr )) new = eval ( x_repr ) print ( new ) print ( "Type of new:" , blazon ( new ))
OUTPUT:
Robot("Marvin",1979) <course 'str'> Proper noun: Marvin, Build Year: 1979 Blazon of new: <class '__main__.Robot'>
Public, - Protected-, and Individual Attributes
Who doesn't know those trigger-happy farmers from films. Shooting as soon every bit somebody enters their property. This "somebody" has of course neglected the "no trespassing" sign, indicating that the land is private property. Mayhap he hasn't seen the sign, possibly the sign is difficult to be seen? Imagine a jogger, running the same course v times a week for more than a year, but than he receives a $50 fine for trespassing in the Winchester Fells. Trespassing is a criminal offence in Massachusetts. He was innocent anyhow, considering the signage was inadequate in the area**.
Even though no trespassing signs and strict laws do protect the private property, some environs their property with fences to keep off unwanted "visitors". Should the fence keep the canis familiaris in the yard or the burglar on the street? Cull your argue: Woods console fencing, mail service-and-rail fencing, chain-link fencing with or without spinous wire and so on.
Nosotros have a like situation in the pattern of object-oriented programming languages. The first determination to take is how to protect the data which should be private. The second determination is what to practise if trespassing, i.e. accessing or changing private data, occurs. Of grade, the individual data may exist protected in a way that it can't be accessed under any circumstances. This is hardly possible in exercise, as nosotros know from the old maxim "Where at that place's a will, there'due south a fashion"!
Some owners allow a restricted access to their property. Joggers or hikers may detect signs like "Enter at your own chance". A third kind of property might be public property like streets or parks, where information technology is perfectly legal to be.
We have the same nomenclature again in object-oriented programming:
- Private attributes should but be used by the owner, i.east. inside of the grade definition itself.
- Protected (restricted) Attributes may be used, just at your own risk. Essentially, they should simply exist used under certain conditions.
- Public Attributes can and should be freely used.
Python uses a special naming scheme for attributes to control the accessibility of the attributes. And so far, we have used attribute names, which can be freely used within or exterior of a course definition, as we accept seen. This corresponds to public attributes of course. There are two means to restrict the access to class attributes:
- First, we can prefix an attribute name with a leading underscore "_". This marks the aspect equally protected. It tells users of the class not to use this attribute unless, they write a bracket. We volition learn about inheritance and subclassing in the side by side affiliate of our tutorial.
- Second, we can prefix an attribute name with two leading underscores "__". The aspect is now inaccessible and invisible from outside. It'southward neither possible to read nor write to those attributes except inside the class definition itself*.
To summarize the attribute types:
Naming | Type | Meaning |
---|---|---|
proper name | Public | These attributes can exist freely used within or outside a class definition. |
_name | Protected | Protected attributes should not be used outside the class definition, unless inside a subclass definition. |
__name | Private | This kind of attribute is inaccessible and invisible. It's neither possible to read nor write to those attributes, except inside the class definition itself. |
We want to demonstrate the behaviour of these aspect types with an example grade:
class A (): def __init__ ( self ): self . __priv = "I am private" cocky . _prot = "I am protected" self . pub = "I am public"
We store this grade (attribute_tests.py) and exam its behaviour in the following interactive Python beat out:
from attribute_tests import A x = A () x . pub
OUTPUT:
10 . pub = ten . pub + " and my value tin can exist changed" x . pub
OUTPUT:
'I am public and my value can exist changed'
OUTPUT:
OUTPUT:
--------------------------------------------------------------------------- AttributeError Traceback (most recent telephone call terminal) <ipython-input-six-f75b36b98afa> in <module> ----> 1x.__priv AttributeError: 'A' object has no attribute '__priv'
The error message is very interesting. One might have expected a message like "__priv
is private". We become the message "AttributeError: 'A' object has no attribute __priv
instead, which looks like a "lie". There is such an aspect, but nosotros are told that there isn't. This is perfect data hiding. Telling a user that an attribute proper noun is private, ways that we make some data visible, i.e. the existence or not-existence of a individual variable.
Our next task is rewriting our Robot class. Though we accept Getter and Setter methods for the name and the build_year, nosotros can access the attributes directly besides, because we have defined them as public attributes. Data Encapsulation means, that nosotros should but be able to access private attributes via getters and setters.
We take to supercede each occurrence of self.name and self.build_year by self.__name
and self.__build_year
.
The listing of our revised form:
course Robot : def __init__ ( cocky , name = None , build_year = 2000 ): cocky . __name = name cocky . __build_year = build_year def say_hi ( self ): if cocky . __name : print ( "Hullo, I am " + cocky . __name ) else : print ( "Howdy, I am a robot without a name" ) def set_name ( self , name ): cocky . __name = name def get_name ( self ): render self . __name def set_build_year ( self , by ): cocky . __build_year = past def get_build_year ( self ): return cocky . __build_year def __repr__ ( self ): render "Robot('" + self . __name + "', " + str ( self . __build_year ) + ")" def __str__ ( self ): return "Name: " + self . __name + ", Build Year: " + str ( self . __build_year ) if __name__ == "__main__" : x = Robot ( "Marvin" , 1979 ) y = Robot ( "Caliban" , 1943 ) for rob in [ x , y ]: rob . say_hi () if rob . get_name () == "Caliban" : rob . set_build_year ( 1993 ) impress ( "I was built in the yr " + str ( rob . get_build_year ()) + "!" )
OUTPUT:
Hello, I am Marvin I was built in the year 1979! Hi, I am Caliban I was built in the year 1993!
Every private attribute of our class has a getter and a setter. There are IDEs for object-oriented programming languages, who automatically provide getters and setters for every individual attribute as before long every bit an attribute is created.
This may look like the following course:
course A(): def __init__(cocky, 10, y): self.__x = ten self.__y = y def GetX(self): render self.__x def GetY(self): render self.__y def SetX(cocky, x): cocky.__x = x def SetY(self, y): self.__y = y
There are at least two skilful reasons confronting such an approach. Get-go of all not every individual aspect needs to be accessed from outside. Second, we will create non-pythonic code this manner, equally you lot will learn before long.
Destructor
What nosotros said near constructors holds true for destructors as well. There is no "real" destructor, just something like, i.e. the method __del__
. It is called when the instance is about to be destroyed and if there is no other reference to this instance. If a base of operations class has a __del__()
method, the derived grade's __del__()
method, if any, must explicitly call it to ensure proper deletion of the base grade role of the case.
The following script is an case with __init__
and __del__
:
grade Robot (): def __init__ ( self , name ): print ( name + " has been created!" ) def __del__ ( self ): impress ( "Robot has been destroyed" ) if __name__ == "__main__" : x = Robot ( "Tik-Tok" ) y = Robot ( "Jenkins" ) z = 10 print ( "Deleting x" ) del 10 print ( "Deleting z" ) del z del y
OUTPUT:
Tik-Tok has been created! Jenkins has been created! Deleting x Deleting z Robot has been destroyed Robot has been destroyed
The usage of the __del__
method is very problematic. If nosotros modify the previous code to personalize the deletion of a robot, nosotros create an error:
form Robot (): def __init__ ( self , name ): impress ( name + " has been created!" ) def __del__ ( self ): print ( cocky . proper name + " says bye-bye!" ) if __name__ == "__main__" : x = Robot ( "Tik-Tok" ) y = Robot ( "Jenkins" ) z = ten print ( "Deleting x" ) del ten print ( "Deleting z" ) del z del y
OUTPUT:
Tik-Tok has been created! Jenkins has been created! Deleting x Deleting z
We are accessing an attribute which doesn't exist anymore. We volition larn later, why this is the case.
Footnotes:
+ The moving picture on the right side is taken in the Library of the Court of Appeal for Ontario, located downtown Toronto in historic Osgoode Hall
++ "Objects are Python's brainchild for data. All information in a Python programme is represented by objects or by relations between objects. (In a sense, and in conformance to Von Neumann's model of a "stored program computer", code is also represented by objects.) Every object has an identity, a type and a value." (excerpt from the official Python Linguistic communication Reference)
+++ "attribute" stems from the Latin verb "attribuere" which means "to associate with"
++++ Jogger ticketed for trespassing
+++++ In that location is a way to admission a individual attribute direct. In our example, we can do it like this: ten._Robot__build_year Y'all shouldn't do this under any circumstances!
Live Python training
Upcoming online Courses
Enrol here
Source: https://python-course.eu/oop/object-oriented-programming.php
Publicar un comentario for "Recall Init Again Object Oriented Programming"