Classes and objects in Python object oriented programming

  • 2020-04-02 14:44:43
  • OfStack

Everything in Python is an object. Class provides a mechanism for creating new types of objects. In this tutorial, we'll skip the basics of classes and object orientation and focus on getting a better understanding of Python object-oriented programming. Suppose we use a new style of python classes that inherit from the object parent.
Define the class

A class statement can define a set of properties, variables, and methods that are Shared by instance objects of that class. Here is a simple class definition:
 


class Account(object):
  num_accounts = 0
 
  def __init__(self, name, balance):
   self.name = name
   self.balance = balance
   Account.num_accounts += 1
 
  def del_account(self):
   Account.num_accounts -= 1
 
  def deposit(self, amt):
   self.balance = self.balance + amt
 
  def withdraw(self, amt):
   self.balance = self.balance - amt
 
  def inquiry(self):
   return self.balance

The class definition introduces the following new objects:

      Class object
      Instance objects
      The method object

Class object

When a class definition is encountered during program execution, a new namespace is created that contains the name bindings for all class variables and method definitions. Note that this namespace does not create a new local scope that class methods can use, so accessing variables in a method requires a fully qualified name. The Account class in the previous section demonstrates this feature; Methods attempting to access the num_of_accounts variable need to use the fully qualified name account.num_of_accounts, otherwise, if you do not use the fully qualified name in the s/s method, the following error will be thrown:
 


class Account(object):
 num_accounts = 0
 
 def __init__(self, name, balance):
  self.name = name
  self.balance = balance
  num_accounts += 1
 
 def del_account(self):
  Account.num_accounts -= 1
 
 def deposit(self, amt):
  self.balance = self.balance + amt
 
 def withdraw(self, amt):
  self.balance = self.balance - amt
 
 def inquiry(self):
  return self.balance
 
>>> acct = Account('obi', 10)
Traceback (most recent call last):
 File "python", line 1, in <module>
 File "python", line 9, in __init__
UnboundLocalError: local variable 'num_accounts' referenced before assignment

At the end of the execution of the class definition, a class object is created. The scope that was valid before entering the class definition is now restored, and the class object is bound to the class name of the class definition header.

Digressing, you might ask if the class you created is an object, what is the class of the class object? . In keeping with the python philosophy that everything is an object, class objects do have a class, the type class in python's new style class.
 


>>> type(Account)
<class 'type'>

To further confuse you, the type of the Account type is type. The type class is a metaclass for creating other classes, which we'll cover later in the tutorial.

Class objects support property references and instantiation. Properties are referenced by the standard point syntax, which is that the object is followed by a period, followed by the property name: obj.name. The valid property names are all variable and method names that appear in the class namespace after the class object is created. Such as:
 


>>> Account.num_accounts
>>> 0
>>> Account.deposit
>>> <unbound method Account.deposit>

Class instantiation USES function notation. Instantiation calls a class object with no arguments, just like a normal function. The following is the Account class:


>>> Account()


After the class object is instantiated, it returns the instance object, which is called if the class defines the method with s/s. This method performs user-defined initialization procedures, such as initialization of instance variables. The Account class is an example where the Account name and balance are set and the number of instance objects is increased by 1.
Instance objects

If the class object is a cookie cutter, the cookie is the result of instantiating the class object. All valid operations on an instance object are references to property, data, and method objects.
The method object

Method objects are similar to function objects. If x is an instance of the Account class, x.deposit is an example of a method object. The method definition has an additional parameter, self. Self points to the class instance. Why do we need to pass an instance to a method as an argument? Method calls best illustrate:
 


>>> x = Account()
>>> x.inquiry()
10

What happens when an instance method is invoked? You should notice that the x.inquiry() call has no arguments, although the method definition contains the self argument. So what happens to this parameter?

The special thing is that the object that the method works on is passed as the first argument to the function. In our example, the call to x.i quiry() is equivalent to account.f (x). In general, the method that invokes the n parameter is equivalent to inserting the action object of the method into the first parameter location.

The python tutorial says:

      When the referenced instance property is not a data property, the class is searched. If the name represents a valid function object, the instance object and the function object are packaged into an abstract object, the method object. When a method object with a parameter list is called, a new parameter list is created based on the instance object and the parameter list, and the function object is called with the new parameter list.

This applies to all instance method objects, including the s/s method. The self parameter is not actually a keyword, and any valid parameter name can be used, as shown in the following Account class definition:
 


class Account(object):
 num_accounts = 0
 
 def __init__(obj, name, balance):
  obj.name = name
  obj.balance = balance
  Account.num_accounts += 1
 
 def del_account(obj):
  Account.num_accounts -= 1
 
 def deposit(obj, amt):
  obj.balance = obj.balance + amt
 
 def withdraw(obj, amt):
  obj.balance = obj.balance - amt
 
 def inquiry(obj):
  return obj.balance
 
>>> Account.num_accounts
>>> 0
>>> x = Account('obi', 0)
>>> x.deposit(10)
>>> Account.inquiry(x)
>>> 10

Static and class methods

Methods defined in a class are called by default by the instance. However, we can also define static or class methods with the corresponding @staticmethod and @classmethod decorators.
A static method

The static way is a normal function in the class namespace. Static methods that reference classes return function types, not unbound method types:
 


class Account(object):
 num_accounts = 0
 
 def __init__(self, name, balance):
  self.name = name
  self.balance = balance
  Account.num_accounts += 1
 
 def del_account(self):
  Account.num_accounts -= 1
 
 def deposit(self, amt):
  self.balance = self.balance + amt
 
 def withdraw(self, amt):
  self.balance = self.balance - amt
 
 def inquiry(self):
  return "Name={}, balance={}".format(self.name, self.balance)
 
 @staticmethod
 def type():
  return "Current Account"
 
>>> Account.deposit
<unbound method Account.deposit>
>>> Account.type
<function type at 0x106893668>

Use the @staticmethod decorator to define static methods that do not require the self parameter. Static methods can better organize the code associated with a class, or they can be overridden in a subclass.
Class method

Class methods are called by the class itself, not the instance. Class methods are defined using the @classmethod decorator, and the first parameter passed to the method is the class, not the instance.
 


import json
 
class Account(object):
 num_accounts = 0
 
 def __init__(self, name, balance):
  self.name = name
  self.balance = balance
  Account.num_accounts += 1
 
 def del_account(self):
  Account.num_accounts -= 1
 
 def deposit(self, amt):
  self.balance = self.balance + amt
 
 def withdraw(self, amt):
  self.balance = self.balance - amt
 
 def inquiry(self):
  return "Name={}, balance={}".format(self.name, self.balance)
 
 @classmethod
 def from_json(cls, params_json):
    params = json.loads(params_json)
  return cls(params.get("name"), params.get("balance"))
 
 @staticmethod
 def type():
  return "Current Account"

A common use of class methods is a factory created as an object. Suppose the Account class has a variety of data formats, such as tuples, json strings, and so on. Since the Python class can only define one method with s/s, class methods are convenient in these cases. The above example is the Account class. We want to initialize an Account according to a json string object. We define a class factory method from_json, which reads the json string object, parses the parameters, and creates the Account object according to the parameters. The other is an example of a class instance (link: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys) method, create it from a set of keys and values in a sequence of dict object.
Python special methods

Sometimes we want to customize a class. This requires changing the way class objects are created and initialized, or providing polymorphic behavior for certain operations. Polymorphic behavior allows you to customize your own implementation of certain python operations such as + in the class definition. Python has a special way of doing this. These methods are usually in the form of *, where * represents the method name. For example, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization, with the custom object creation and initialization. Only a handful of special methods, we discuss some important special methods to do a simple understanding, (link: https://docs.python.org/2/reference/datamodel.html#basic-customization) has a list of all methods.
Special method for object creation

The new class instance is created by a two-stage process, with the new instance being created by the method, and the instance being initialized by arbitration. The user is already familiar with the definition of the method of s/s. However, the user rarely defines the method, but if you want to customize the creation of class instances, you can.
Special method for property access

We can customize property access for class instances by implementing the following methods.


class Account(object):
 num_accounts = 0
 
 def __init__(self, name, balance):
  self.name = name
  self.balance = balance
  Account.num_accounts += 1
 
 def del_account(self):
  Account.num_accounts -= 1
 
 def __getattr__(self, name):
  return "Hey I dont see any attribute called {}".format(name)
 
 def deposit(self, amt):
  self.balance = self.balance + amt
 
 def withdraw(self, amt):
  self.balance = self.balance - amt
 
 def inquiry(self):
  return "Name={}, balance={}".format(self.name, self.balance)
 
 @classmethod
 def from_dict(cls, params):
  params_dict = json.loads(params)
  return cls(params_dict.get("name"), params_dict.get("balance"))
 
 @staticmethod
 def type():
  return "Current Account"
 
x = Account('obi', 0)

      This method is called only if the name is neither an instance attribute nor can be found in the class inheritance chain of the object. This method should either return an attribute value or throw an AttributeError exception. For example, if x is an instance of the Account class, an attempt to access a nonexistent property will invoke this method.
 


>>> acct = Account("obi", 10)
>>> acct.number
Hey I dont see any attribute called number

Note that there may be a dead loop if you refer to a non-existent instance attribute, as the method is continually being called.

2. Successive setattr__(self, name, value)__ : this method is called when an attribute assignment occurs. Instead of using self.name=value, the value will be inserted into the instance property dictionary, as this will result in a dead loop of the recursive call.

Call: del obj while happening.

4. Getattribute__ (self, name)__ : this method will be called all the time to access the attributes of the class instance.
A special method for type simulation

For certain types, Python defines certain syntax; For example, elements of lists and tuples can be accessed by index notation, numeric values can be added by the + operator, and so on. We can create our own classes that use these special grammars, and the python interpreter will call the methods we implement when it encounters these special grammars. We demonstrate this feature with a simple example below that simulates the basic usage of python lists.


class CustomList(object):
 
 def __init__(self, container=None):
  # the class is just a wrapper around another list to
  # illustrate special methods
  if container is None:
   self.container = []
  else:
   self.container = container
 
 def __len__(self):
  # called when a user calls len(CustomList instance)
  return len(self.container)
 
 def __getitem__(self, index):
  # called when a user uses square brackets for indexing
  return self.container[index]
 
 def __setitem__(self, index, value):
  # called when a user performs an index assignment
  if index &lt;= len(self.container):
   self.container[index] = value
  else:
   raise IndexError()
 
 def __contains__(self, value):
  # called when the user uses the 'in' keyword
  return value in self.container
 
 def append(self, value):
  self.container.append(value)
 
 def __repr__(self):
  return str(self.container)
 
 def __add__(self, otherList):
  # provides support for the use of the + operator
  return CustomList(self.container + otherList.container)

Above, CustomList is a simple wrapper around a real list. We implemented some custom methods for demonstration purposes:

      S/s (self) : called when the len() function is called on the CustomList instance.


>>> myList = CustomList()
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> len(myList)
4

2. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 


>>> myList = CustomList()
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> myList[3]
4

3. S/s (self, key, value) : called when self[key] is assigned on the CustomList class instance.
 


>>> myList = CustomList()
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> myList[3] = 100
4
>>> myList[3]
100

4. Contains__ (self, key) : called during member detection. Returns true if an item is included, or false otherwise.
 


>>> myList = CustomList()
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> 4 in myList
True

5. S/p (self) : called when printing self with print, the object representation of self will be printed.
 


>>> myList = CustomList()
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> print myList
[1, 2, 3, 4]

6. S/s (self, otherList) : called when two CustomList instances are added using the + operator.
 


>>> myList = CustomList()
>>> otherList = CustomList()
>>> otherList.append(100)
>>> myList.append(1) 
>>> myList.append(2)
>>> myList.append(3)
>>> myList.append(4)
>>> myList + otherList + otherList
[1, 2, 3, 4, 100, 100]

The above example demonstrates how to customize class behavior by defining some special class methods. Can be in (link: https://docs.python.org/2/reference/datamodel.html#basic-customization) to view a complete list of these custom method. In the following tutorials, we will put together a discussion of special methods and explain descriptors, an important feature that is widely used in python object-oriented programming.


Related articles: