python SET3

Réussis tes devoirs et examens dès maintenant avec Quizwiz!

property to an object

Now let's add just one property to the new object - a list for a stack. We'll name it stack_list. Just like here: class Stack: def __init__(self): self.stack_list = [] stack_object = Stack() print(len(stack_object.stack_list))

the super() function

accesses the superclass without needing to know its name: super().__init__() Note: you can use this mechanism not only to invoke the superclass constructor, but also to get access to any of the resources available inside the superclass.

subclass, superclass

adding a new property to the class is done by the constructor. You already know how to do that, but there is something really intriguing inside the constructor. Take a look: class AddingStack(Stack): def __init__(self): Stack.__init__(self) self.__sum = 0 The second line of the constructor's body creates a property named __sum - it will store the total of all the stack's values. But the line before it looks different. What does it do? Is it really necessary? Yes, it is. Contrary to many other languages, Python forces you to explicitly invoke a superclass's constructor.

subclass, superclass

class AddingStack(Stack): def __init__(self): Stack.__init__(self) self.__sum = 0 Note the syntax: -you specify the superclass's name (this is the class whose constructor you want to run) -you put a dot (.)after it; -you specify the name of the constructor; -you have to point to the object (the class's instance) which has to be initialized by the constructor - this is why you have to specify the argument and use the self variable here; note: invoking any method (including constructors) from outside the class never requires you to put the self argument at the argument's list - invoking a method from within the class demands explicit usage of the self argument, and it has to be put first on the list.

subclass, superclass

class AddingStack(Stack): pass The class doesn't define any new component yet, but that doesn't mean that it's empty. It gets all the components defined by its superclass (ie. Stack)

Polymorphism

class One: def do_it(self): print("do_it from One") def doanything(self): self.do_it() class Two(One): def do_it(self): print("do_it from Two") one = One() two = Two() one.doanything() two.doanything() output: do_it from One do_it from Two Note: the situation in which the subclass is able to modify its superclass behavior (just like in the example) is called polymorphism. The method, redefined in any of the superclasses, thus changing the behavior of the superclass, is called virtual.

Multiple Inheritance

Multiple inheritance occurs when a class has more than one superclass.

more of class

1. A class is an idea (more or less abstract) which can be used to create a number of incarnations - such an incarnation is called an object. 2. When a class is derived from another class, their relation is named inheritance. The class which derives from the other class is named a subclass. The second side of this relation is named superclass. A way to present such a relation is an inheritance diagram, where: superclasses are always presented above their subclasses; relations between classes are shown as arrows directed from the subclass toward its superclass.

class object

A class (among other definitions) is a set of objects. An object is a being belonging to a class. An object is an incarnation of the requirements, traits, and qualities assigned to a specific class. This may sound simple, but note the following important circumstances. Classes form a hierarchy

a class method

A class method is actually a function declared inside the class and able to access all the class's components.

class variable

A class variable is a property which exists in just one copy and is stored outside any object. Note: no instance variable exists if there is no object in the class; a class variable exists in one copy even if there are no objects in the class.

two underscores means??

A name starting with two underscores (__), it becomes private - this means that it can be accessed only from within the class. You cannot see it from the outside world. This is how Python implements the encapsulation concept

What is a stack?

A stack is a structure developed to store data in a very specific way

A Stack

A stack is an object designed to store data using the LIFO model. The stack usually accomplishes at least two operations, named push() and pop(). Implementing the stack in a procedural model raises several problems which can be solved by the techniques offered by OOP (Object Oriented Programming):

Stack

A stack is an object with two elementary operations, conventionally named push (when a new element is put on the top) and pop (when an existing element is taken away from the top).

__dict__, __name__, __module__, __bases__ These means allow?

All these means allow the Python programmer to perform two important activities specific to many objective languages. They are: introspection, which is the ability of a program to examine the type or properties of an object at runtime; reflection, which goes a step further, and is the ability of a program to manipulate the values, properties and/or functions of an object at runtime.

more on __dict__

Can be used on method's and classes too

self

Each class method declaration must contain at least one parameter (always the first one) usually referred to as self, and is used by the objects to identify themselves.

class -- subclass

Each subclass is more specialized (or more specific) than its superclass. Conversely, each superclass is more general (more abstract) than any of its subclasses

class

Every class is like a recipe which can be used when you want to create a useful object (this is where the name of the approach comes from). You may produce as many objects as you need to solve your problem.

object

Every object has a set of traits (they are called properties or attributes - we'll use both words synonymously) and is able to perform a set of activities (which are called methods) Objects are incarnations of ideas expressed in classes The objects interact with each other, exchanging data or activating their methods. A properly constructed class (and thus, its objects) are able to protect the sensible data and hide it from unauthorized modifications. There is no clear border between data and code: they live as one in objects. All these concepts are not as abstract as you may at first suspect. On the contrary, they all are taken from real-life experiences, and therefore are extremely useful in computer programming: they don't create artificial life - they reflect real facts, relationships, and circumstances

Inheritance

Inheritance is a common practice (in object programming) of passing attributes and methods from the superclass (defined and existing) to a newly created class, called the subclass.

the self parameter

It allows the method to access entities (properties and activities/methods) carried out by the actual object. You cannot omit it. Every time Python invokes a method, it implicitly sends the current object as the first argument. This means that a method is obligated to have at least one parameter, which is used by Python itself - you don't have any influence on it.

class ExampleClass: counter = 0 def __init__(self, val = 1): self.__first = val ExampleClass.counter += 1 example_object_1 = ExampleClass() example_object_2 = ExampleClass(2) example_object_3 = ExampleClass(4) print(example_object_1.__dict__, example_object_1.counter) print(example_object_2.__dict__, example_object_2.counter) print(example_object_3.__dict__, example_object_3.counter)

Look: there is an assignment in the first list of the class definition - it sets the variable named counter to 0; initializing the variable inside the class but outside any of its methods makes the variable a class variable; accessing such a variable looks the same as accessing any instance attribute - you can see it in the constructor body; as you can see, the constructor increments the variable by one; in effect, the variable counts all the created objects.

What is Method Resolution Order (MRO) and why is it that not all inheritances make sense?

MRO, in general, is a way (you can call it a strategy) in which a particular programming language scans through the upper part of a class's hierarchy in order to find the method it currently needs. Python's MRO cannot be bent or violated, not just because that's the way Python works, but also because it's a rule you have to obey.

procedural vs the object-oriented approach

Procedural vs. the object-oriented approach In the procedural approach, it's possible to distinguish two different and completely separate worlds: the world of data, and the world of code. The world of data is populated with variables of different kinds, while the world of code is inhabited by code grouped into modules and functions.

python is a tool for what?

Python is a universal tool for both object and procedural programming

looking for object components

Python looks for object components in the following order: inside the object itself; in its superclasses, from bottom to top; if there is more than one class on a particular inheritance path, Python scans them from left to right.

Python objects -- __dict__

Python objects, when created, are gifted with a small set of predefined properties and methods. Each object has got them, whether you want them or not. One of them is a variable named __dict__ (it's a dictionary). The variable contains the names and values of all the properties (variables) the object is currently carrying

hasattr

Python provides a function which is able to safely check if any object/class contains a specified property expects two arguments to be passed to it: the class or the object being checked; the name of the property whose existence has to be reported (note: it has to be a string containing the attribute name, not the name alone) The function returns True or False. example_object = ExampleClass(1) print(example_object.a) if hasattr(example_object, 'b'): print(example_object.b)

class ExampleClass: counter = 0 def __init__(self, val = 1): self.__first = val ExampleClass.counter += 1 example_object_1 = ExampleClass() example_object_2 = ExampleClass(2) example_object_3 = ExampleClass(4) print(example_object_1.__dict__, example_object_1.counter) print(example_object_2.__dict__, example_object_2.counter) print(example_object_3.__dict__, example_object_3.counter)

Running the code will cause the following output: {'_ExampleClass__first': 1} 3 {'_ExampleClass__first': 2} 3 {'_ExampleClass__first': 4} 3 Two important conclusions come from the example: class variables aren't shown in an object's __dict__ (this is natural as class variables aren't parts of an object) but you can always try to look into the variable of the same name, but at the class level - we'll show you this very soon; a class variable always presents the same value in all class instances (objects)

LIFO

The alternative name for a stack (but only in IT terminology) is LIFO. It's an abbreviation for a very clear description of the stack's behavior: Last In - First Out

is operator

The is operator checks whether two variables (object_one and object_two here) refer to the same object. Don't forget that variables don't store the objects themselves, but only the handles pointing to the internal Python memory. The is operator checks whether two variables (object_one and object_two here) refer to the same object.

more on self

The name self suggests the method's parameter's purpose - it identifies the object for which the method is invoked. The self parameter is used to obtain access to the object's instance and class variables. The self parameter is also used to invoke other object/class methods from inside the class.

the obect approach

The object approach suggests a completely different way of thinking. The data and the code are enclosed together in the same world, divided into classes.

What does an object have?

The object programming convention assumes that every existing object may be equipped with three groups of attributes: an object has a name that uniquely identifies it within its home namespace (although there may be some anonymous objects, too) an object has a set of individual properties which make it original, unique, or outstanding (although it's possible that some objects may have no properties at all) an object has a set of abilities to perform specific activities, able to change the object itself, or some of the other objects.

__init__

The part of the Python class responsible for creating new objects is called the constructor, and it's implemented as a method of the name __init__.

args

The syntax except Exception_Name as an exception_object: lets you intercept an object carrying information about a pending exception. The object's property named args (a tuple) stores all arguments passed to the object's constructor

__str__() method

When Python needs any class/object to be presented as a string (putting an object as an argument in the print() function invocation fits this condition) it tries to invoke a method named __str__() from the object and to use the string it returns. The default __str__() method returns the previous string - ugly and not very informative. You can change it just by defining your own method of the name. A method named __str__() is responsible for converting an object's contents into a (more or less) readable string.

Private instance variables ___.

When Python sees that you want to add an instance variable to an object and you're going to do it inside any of the object's methods, it mangles the operation in the following way: it puts a class name before your name; it puts an additional underscore at the beginning. This is why the __first becomes _ExampleClass__first. The name is now fully accessible from outside the class. You can run a code like this: print(example_object_1._ExampleClass__first) and you'll get a valid result with no errors or exceptions. As you can see, making a property private is limited.

accessing objects properties or entities

When you try to access any object's entity, Python will try to (in this order): find it inside the object itself; find it in all classes involved in the object's inheritance line from bottom to top; If both of the above fail, an exception (AttributeError) is raised.

__bases__

__bases__ is a tuple. The tuple contains classes (not class names) which are direct superclasses for the class. Note: only classes have this attribute - objects don't. shows inheritance Note: a class without explicit superclasses points to object (a predefined Python class) as its direct ancestor.

__module__

__module__ is a string, too - it stores the name of the module which contains the definition of the class. class Classy: pass print(Classy.__module__) obj = Classy() print(obj.__module__) The code outputs: __main__ __main__ As you know, any module named __main__ is actually not a module, but the file currently being run.

__name__

__name__, which is a string. The property contains the name of the class. It's nothing exciting, just a string. Note: the __name__ attribute is absent from the object - it exists only inside classes. If you want to find the class of a particular object, you can use a function named type(), which is able (among other things) to find a class which has been used to instantiate any object. print(Classy.__name__) obj = Classy() print(type(obj).__name__)

more on __init__

a constructor. is obliged to have the self parameter (it's set automatically, as usual); may (but doesn't need to) have more parameters than just self; if this happens, the way in which the class name is used to create the object must reflect the __init__ definition; can be used to set up the object, i.e., properly initialize its internal state, create instance variables, instantiate any other objects if their existence is needed, etc. cannot return a value, as it is designed to return a newly created object and nothing else; cannot be invoked directly either from the object or from inside the class (you can invoke a constructor from any of the object's subclasses, but we'll discuss this issue later.)

a function inside a class is

a method

More on methods

a method is a function embedded inside a class. a method is obliged to have at least one parameter

Sample

class Sample: gamma = 0 # Class variable. def __init__(self): self.alpha = 1 # Instance variable. self.__delta = 3 # Private instance variable. obj = Sample() obj.beta = 2 # Another instance variable (existing only inside the "obj" instance.) print(obj.__dict__) The code outputs: {'alpha': 1, '_Sample__delta': 3, 'beta': 2}

class Cars:

class is a keyword The keyword is followed by an identifier which will name the class (note: don't confuse it with the object's name - these are two different things).

try: except: else: finally:

def reciprocal(n): try: n = 1 / n except ZeroDivisionError: print("Division failed") n = None else: print("Everything went fine") finally: print("It's time to say goodbye") return n print(reciprocal(2)) print(reciprocal(0)) Note: these two variants (else and finally) aren't dependent in any way, and they can coexist or occur independently. The finally block is always executed (it finalizes the try-except block execution, hence its name), no matter what happened earlier, even when raising an exception, no matter whether this has been handled or not.

try: except: else:

def reciprocal(n): try: n = 1 / n except ZeroDivisionError: print("Division failed") return None else: print("Everything went fine") return n print(reciprocal(2)) print(reciprocal(0)) Note: the else: branch has to be located after the last except branch.

Instance variable

different objects of the same class may possess different sets of properties; there must be a way to safely check if a specific object owns the property you want to utilize (unless you want to provoke an exception - it's always worth considering) each object carries its own set of properties - they don't interfere with one another in any way. Such variables (properties) are called instance variables.

Inheritance

inheritance is a way of building a new class, not from scratch, but by using an already defined repertoire of traits. Thanks to that, it's possible to build more specialized (more concrete) classes using some sets of predefined general rules and behaviors

inheritance

inheritance. Any object bound to a specific level of a class hierarchy inherits all the traits (as well as the requirements and qualities) defined inside any of the superclasses.

Compostition

is the process of composing an object using other different objects. It can be said that: inheritance extends a class's capabilities by adding new components and modifying existing ones; in other words, the complete recipe is contained inside the class itself and all its ancestors; the object takes all the class's belongings and makes use of them; composition projects a class as a container able to store and use other objects (derived from other classes) where each of the objects implements a part of a desired class's behavior.

isinstance()

isinstance() As you already know, an object is an incarnation of a class. it can be crucial if the object does have (or doesn't have) certain characteristics. In other words, whether it is an object of a certain class or not. Such a fact could be detected by the function named isinstance(): isinstance(objectName, ClassName) The functions returns True if the object is an instance of the class, or False otherwise. Being an instance of a class means that the object (the cake) has been prepared using a recipe contained in either the class or one of its superclasses.

issubclass()

issubclass() a function which is able to identify a relationship between two classes, and although its diagnosis isn't complex, it can check if a particular class is a subclass of any other class issubclass(ClassOne, ClassTwo) There is one important observation to make: each class is considered to be a subclass of itself.

class TheSimplestClass(): pass my_first_object = TheSimplestClass()

my_first_object = TheSimplestClass() Note: the newly created object is equipped with everything the class brings; as this class is completely empty, the object is empty, too. The act of creating an object of the selected class is also called an instantiation (as the object becomes an instance of the class).

using dot notation to access an object's

property/s

Encapsulation

the ability to hide (protect) selected values against unauthorized access is called encapsulation; the encapsulated values can be neither accessed nor modified if you want to use them exclusively;

Object programming is -

the art of defining and expanding classes

class ExampleClass: def __init__(self, val = 1): self.first = val def set_second(self, val): self.second = val example_object_1 = ExampleClass() example_object_2 = ExampleClass(2) example_object_2.set_second(3) example_object_3 = ExampleClass(4) example_object_3.third = 5 print(example_object_1.__dict__) print(example_object_2.__dict__) print(example_object_3.__dict__)

the class named ExampleClass has a constructor, which unconditionally creates an instance variable named first, and sets it with the value passed through the first argument (from the class user's perspective) or the second argument (from the constructor's perspective); note the default value of the parameter - any trick you can do with a regular function parameter can be applied to methods, too; the class also has a method which creates another instance variable, named second; we've created three objects of the class ExampleClass, but all these instances differ: example_object_1 only has the property named first; example_object_2 has two properties: first and second; example_object_3 has been enriched with a property named third just on the fly, outside the class's code - this is possible and fully permissible. The program's output clearly shows that our assumptions are correct - here it is: {'first': 1} {'second': 3, 'first': 2} {'third': 5, 'first': 4} output There is one additional conclusion that should be stated here: modifying an instance variable of any object has no impact on all the remaining objects. Instance variables are perfectly isolated from each other.

hasattr --- classes

the hasattr() function can operate on classes, too. You can use it to find out if a class variable is available, class ExampleClass: attr = 1 print(hasattr(ExampleClass, 'attr')) print(hasattr(ExampleClass, 'prop'))

exceptions are classes

try: i = int("Hello!") except Exception as e: print(e) print(e.__str__())

__init__

you have to equip the class with a specific function - its specificity is dual: it has to be named in a strict way; it is invoked implicitly, when the new object is created. Such a function is called a constructor, as its general purpose is to construct a new object. The constructor should know everything about the object's structure, and must perform all the needed initializations. the constructor's name is always __init__; it has to have at least one parameter (we'll discuss this later); the parameter is used to represent the newly created object - you can use the parameter to manipulate the object, and to enrich it with the needed properties; you'll make use of this soon; note: the obligatory parameter is usually named self - it's only a convention, but you should follow it - it simplifies the process of reading and understanding your code.


Ensembles d'études connexes

BMAL-590 Information Management Systems

View Set

Chapter 32: Skin Integrity and Wound Care pt. 2

View Set

Respiratory System: Gas Exchange

View Set

Study set for Michigan's drivers test

View Set

Chapter 24 (actually chapter 17)

View Set

Montagu/ Rowlatt Acts/ Amritsar/Gov of India Act 1919

View Set

Prep U Adults 2 Exam 1 (Ch 13, 32, 33, 34, 35, 53, 54, 55, 56, 57, 58, 59)

View Set