Advanced Python: Python's object-oriented attribute method

Keywords: Python Back-end Programmer

This time, we mainly introduce various properties defined in the class, such as class properties, instance properties, private properties of the class, and various methods, such as instance methods, class methods, static methods, and   Property property method and other related knowledge.

🚀 Look at a piece of code

class Tool(object):
    dog_type = "Huskie"  # Class properties

    def __init__(self,name):
        self.name = name  # Instance properties
    
    # Example method
    def tell_info(self):
        pass
    
    # Class method
    @classmethod
    def bar(cls): 
        pass
    
    # Static method
    @staticmethod
    def foo(x):
        pass
    
    #Attribute method
    @property
    def tell_name(self):
        return self.name
 Copy code

Class properties and instance properties

Both class attributes and instance attributes are defined in the class, but the fundamental difference is that the saved location is different from the called object. For example:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   dog.py
@Time    :   2019/10/23 15:00:58
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Dogs(object):
    # Class properties
    belongTo = "Animals"

    def __init__(self, name):
        #Instance properties
        self.name = name


dog1 = Dogs("Sunny Chen")
print(Dogs.belongTo)  # Class properties are accessed through classes
print(dog1.name)  # Instance properties are accessed through instances
print(dog1.belongTo)  #Class properties can also be accessed by instances
# print(Dogs.name)  # However, instance properties cannot be accessed by the class
 Copy code

Class properties can be accessed by classes and properties, while instance properties can only be accessed by instances because:

This is because each time an instance object is created through a class, a memory space will be opened up to store the properties and methods of the instance object and the pointer of the class object. The reason why the instance object can call the methods in the class is that the properties and methods of the class can be accessed through the class object pointer.

However, if the instance object wants to modify the properties and methods of the class, it needs to use special methods. For example:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   dog.py
@Time    :   2019/10/23 15:03:56
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Dogs(object):
    # Class properties
    belongTo = "Animals"

    def __init__(self, name):
        #Instance properties
        self.name = name


dog1 = Dogs("Sunny Chen")

dog1.belongTo = "wakka"
print(Dogs.belongTo)  #Animals
# Note: the class attribute cannot be modified in this way, but it is overridden in the attribute dictionary of the instance
print(dog1.__dict__)  #{'name': 'Sunny Chen', 'belongTo': 'wakka'}

dog1.__class__.belongTo = "Wakka"
print(Dogs.belongTo)  # Wakka -- modified successfully
 Copy code

Instance method, class method and static method

Instance method: usually called by an object, the instance object must be passed in. When the instance method is executed, the instance object calling the method itself will be automatically passed to the self parameter of the method.

Class method: it is usually called by a class, and the class object itself must be passed in. When the class method is executed, the class object calling the method is automatically assigned to the cls parameter;

Static method: class and instance objects can be called without passing instance objects and class objects, and there are no default parameters.

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   testDemo.py
@Time    :   2019/10/23 15:09:21
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Test(object):
    def __init__(self, name):
        self.name = name

    #Example method
    def mm(self):
        print("in the mm")

    #Class method
    @classmethod
    def tt(cls):
        print("in the tt")
        print(cls)

    #Static method
    @staticmethod
    def gg(a):
        print("in the gg", a)


test1 = Test("alex")
test1.mm()
test1.tt()  # If an instance can call a class method, the class object is passed in -- < class' by default__ main__. Test'>
test1.gg(100)

Test.mm(test1)  # Class object calling instance method must pass in a class
Test.tt()
Test.gg(100)
Copy code

Same point: all methods belong to class (non object), so only one copy is saved in memory.

Differences: the method callers are different, and the parameters automatically passed in when calling the method are different.

Functions of class methods and static methods:

Class methods: class methods are mainly used to manage class attributes, whether private or ordinary. In many classes, instantiation may not be necessary, just for encapsulation. At this time, we can manage class attributes through class methods.  

Static method: when we have many messy and unrelated functions, we need to encapsulate the functions in classes, but we cannot modify the code or parameters of the functions, just to encapsulate these functions through classes for management. For example:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   toolDemo2.py
@Time    :   2019/10/23 15:11:13
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Tool(object):
    """
    Define a toolbox to manage these tools, just to encapsulate without affecting these functions, so as to facilitate management
    """
    @staticmethod
    def hammer():  # hammer
        pass

    @staticmethod
    def ax():  # axe
        pass

    @staticmethod
    def wrench():  # Wrench
        pass


# When we need to use these tools, we can call them directly with class objects
# At the same time, no additional parameters are passed in, such as self instance itself and cls class itself, just to achieve the effect of encapsulation
Tool.hammer()
Tool.ax()
Copy code

Attribute method property

The literal meaning is to make the method a special attribute, that is, a special attribute used like the instance attribute used, which can correspond to a method. For example:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   testDemo.py
@Time    :   2019/10/23 15:13:21
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Test(object):
    def foo(self):
        print("in the fo")

    # Define property properties
    @property
    def bar(self):
        # print("in the bar")
        return "in the bar"


tt = Test()
tt.foo()  # Call normal instance method -- in the fo
ret = tt.bar  # The calling method is the same as the class attribute, and also has a return value -- in the bar
print(ret)
Copy code

When defining, add the @ property decorator to the instance method, and there is only one self parameter;

When called, it is the same as calling class properties, without parentheses

# For the list page of the computer host displayed in Jingdong Mall, it is impossible to display all the contents in the database on the page each time. Instead, it is displayed locally through the paging function. Therefore, when requesting data from the database, it is necessary to obtain all the data from item m to item n. the paging functions include:

# Calculate m and n according to the current page and the total number of data requested by the user
# Request data from the database according to m and n


class Pager:
    def __init__(self, current_page):
        # Page number currently requested by the user (first page, second page...)
        self.current_page = current_page
        # Each page displays 10 pieces of data by default
        self.per_items = 10

    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val


# call
p = Pager(1)
p.start  # Is the starting value, i.e. m
p.end  # Is the end value, i.e. n
 Copy code

Summary: @ property is a decorator that transforms a method into a special property. Since it is a property, there will be additions, deletions, modifications and deletions (calls, modifications and deletions). Let's see how to implement the additions, deletions, modifications and deletions of the property property.

property Adding, deleting, modifying and querying attributes (two methods):

There are two ways:

  1. There are three @ property decorators;
  2. Class attribute method, create a class attribute with a value of property object

Three @ property decorators

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   goodDemo.py
@Time    :   2019/10/23 15:17:57
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib

# Method 1: through the decorator, when an operation is performed, the execution (copy) of the decorator and the method under the decorator is automatically triggered

class Goods(object):
    def __init__(self):
        # original price
        self.original_price = 100
        # discount
        self.discount = 0.8

    @property
    def price(self):
        # Actual price = original price * discount
        new_price = self.original_price * self.discount
        return new_price

    @price.setter  # func_name.setter
    def price(self, value):
        self.original_price = value

    @price.deleter  # func_name.deleter
    def price(self, value):
        del self.original_price


obj = Goods()
obj.price  # Get commodity price
obj.price = 200  # Modify original price of goods
del obj.price  # Delete original price of goods

# Analysis: it is a bit similar to magic. When an operation is performed, the operation of the decorator is automatically triggered
#   @Property -- when the price property is obtained, the method modified by @ property is automatically executed and the return value of the method is obtained, such as obj.func
#    @Func.setter -- when setting and modifying the price property, automatically execute the func method modified by @ func.setter, and assign the value to the parameter of the method, for example: obj.func = 200
#    @Func.deleter -- when the price attribute is deleted, the func method modified by @ func.deleter is automatically executed
 Copy code

Class attribute method, the creation value is  property Class properties of the object

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   fooDemo.py
@Time    :   2019/10/23 15:20:30
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib


class Foo(object):
    def get_bar(self):
        num = 100
        return num

    def set_bar(self, value):
        """Two parameters are required"""
        num = value
        return num

    def del_bar(self):
        num = 100
        del num
        return "deleted this attribute"

    #The sequence can not be wrong, including get, modify, delete and description
    BAR = property(get_bar, set_bar, del_bar, "description...")


obj = Foo()

obj.BAR  # Automatically call the method defined in the first parameter: get_bar
obj.BAR = 200  # Automatically call the method defined in the second parameter: set_bar method and pass 200 as a parameter
del obj.BAR  # Automatically call the method defined in the third parameter: del_bar method
desc = Foo.BAR.__doc__  # Automatically get the value set in the fourth parameter: description
print(desc)
print(obj.BAR)
Copy code

about property The use of attributes is very common and has obvious advantages:

It provides users with a simple attribute instead of a complex function (considering the parameters of the function and the return value of the function), and only gets the return value of the function by calling the attribute. In essence, it is also the embodiment of encapsulation, that is, encapsulating the underlying complex implementation, and providing users with a simple and usable attribute interface. Here are the codes for large companies:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   messageDemo.py Tencent instant messaging module-reference resources
@Time    :   2019/10/23 15:28:04
@Author  :   YongJia Chen 
@Version :   1.0
@Contact :   chen867647213@163.com
@License :   (C)Copyright 2018-2019, Liugroup-NLPR-CASIA
@Desc    :   None
'''

# here put the import lib

# coding: utf-8

import random
import time


class Message(object):
    def __init__(self, msgarr=[], toacc=''):
        self.msgbody = msgarr  # Here is the list or empty list of MsgDict object instances
        self.toacc = toacc  # toacc is string (single issue) or list (batch issue)
        self.msgrandom = random.randint(1, 1000000000)
        self.msgrequest = {
            'To_Account': toacc,  # Message receiver account
            'MsgRandom': self.msgrandom,  # Message random number, generated by random function
            'MsgBody': [t.msg for t in msgarr]
        }

    def del_option(self, option):
        if option in (set(self.msgrequest) -
                      set(['To_Account', 'MsgRandom', 'MsgBody'])):
            self.__dict__.pop(option)
            self.msgrequest.pop(option)

    def append_msg(self, msg):
        self.msgbody.append(msg)
        self.msgrequest['MsgBody'].append(msg.msg)

    def insert_msg(self, index, msg):
        self.msgbody.insert(index, msg)
        self.msgrequest['MsgBody'].insert(msg.msg)

    def del_msg(self, index):
        if index in range(len(self.msgbody)):
            del self.msgbody[index]
            del self.msgrequest['MsgBody'][index]

    def set_from(self, fromacc):
        # Specifies the sender of the message, which is sent by the server by default
        self.fromacc = fromacc
        self.msgrequest['From_Account'] = fromacc

    def set_to(self, toacc):
        # Specify the receiver of the message, which can be string (single send) or list (batch send)
        self.toacc = toacc
        self.msgrequest['To_Account'] = toacc

    def refresh_random(self):
        self.msgrandom = random.randint(1, 1000000000)
        self.msgrequest['MsgRandom'] = self.msgrandom,  # Message random number, generated by random function

    def set_sync(self, sync):
        # Synchronization options: 1. Synchronize messages to From_Account online terminal and roaming
        #           2. The message is not synchronized to From_Account
        #           If it is not filled in, the message will be synchronized by default
        #           Can only be called in single issue single chat messages
        self.sync = sync
        self.msgrequest['SyncOtherMachine'] = sync

    def set_timestamp(self):
        # Set the message timestamp and unix time, which can be called only in single issue single chat messages
        self.timestamp = int(time.time())
        self.msgrequest['MsgTimeStamp'] = self.timestamp

    def set_offlinepush(self, pushflag=0, desc='', ext='', sound=''):
        # It is only applicable to APNa push, not Android push
        self.msgrequest['OfflinePushInfo'] = {
            'PushFlag': pushflag,
            'Desc': desc,
            'Ext': ext,
            'Sound': sound
        }


class MsgDict(object):
    def __init__(self, msgtype='', msgcontent={}):
        self.msgtype = msgtype
        self.msgcontent = msgcontent

    @property
    def msg(self):
        return {'MsgType': self.msgtype, 'MsgContent': self.msgcontent}

    def set_content(self, content):
        self.msgcontent = content


class TextMsg(MsgDict):
    def __init__(self, text='', msgtype='TIMTextElem'):
        self.text = text
        content = {'Text': text}
        super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_text(self, text):
        self.text = text
        self.msgcontent['Text'] = text


class LocationMsg(MsgDict):
    def __init__(self,
                 desc='',
                 latitude=0,
                 longitude=0,
                 msgtype='TIMLocationElem'):
        self.desc = desc
        self.latitude = latitude
        self.longitude = longitude
        content = {
            'Desc': desc,  # Geographic location description information, String
            'Latitude': latitude,  # Latitude, Number
            'Longitude': longitude  # Longitude, Number
        }
        super(LocationMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_desc(self, desc):
        self.desc = desc
        self.msgcontent['Desc'] = desc

    def set_location(self, latitude, longitude):
        self.latitude = latitude
        self.longitude = longitude
        self.msgcontent['Latitude'] = latitude
        self.msgcontent['Longitude'] = longitude

    def set_latitude(self, latitude):
        self.latitude = latitude
        self.msgcontent['Latitude'] = latitude

    def set_longitude(self, longitude):
        self.longitude = longitude
        self.msgcontent['Longitude'] = longitude


class FaceMsg(MsgDict):
    def __init__(self, index=1, data='', msgtype='TIMFaceElem'):
        self.index = index
        self.data = data
        content = {
            'Index': index,  # Expression index, user defined, Number
            'Data': data  # Extra data, String
        }
        super(TextMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_index(self, index):
        self.index = index
        self.msgcontent['Index'] = index

    def set_data(self, data):
        self.data = data
        self.msgcontent['Data'] = data


class CustomMsg(MsgDict):
    def __init__(self,
                 data='',
                 desc='',
                 ext='',
                 sound='',
                 msgtype='TIMCustomElem'):
        self.data = data
        self.desc = desc
        self.ext = ext
        self.sound = sound
        content = {
            'Data':
            data,  # Custom message Data. It is not distributed as a field in the payload of APNS, so the Data field cannot be obtained from the payload, String
            'Desc': desc,  # User defined message description. When the receiver is online in the background of iphone, it will be displayed as text when ios is offline Push
            'Ext':
            ext,  # Extended field. When the receiver is the ios system and the application is in the background, this field is issued as the EXT key value in the APNS request package Payloads. The protocol format of ext is determined by the business party, and APNS only performs transparent transmission
            'Sound': sound  # Custom APNS push ringtone
        }
        super(CustomMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_data(self, data):
        self.data = data
        self.msgcontent['Data'] = data

    def set_desc(self, desc):
        self.desc = desc
        self.msgcontent['Desc'] = desc

    def set_ext(self, ext):
        self.ext = ext
        self.msgcontent['Ext'] = ext

    def set_sound(self, sound):
        self.sound = sound
        self.msgcontent['Sound'] = sound


class SoundMsg(MsgDict):
    def __init__(self, uuid='', size=0, second=0, msgtype='TIMSoundElem'):
        self.uuid = uuid
        self.size = size
        self.second = second
        content = {
            'UUID': uuid,  # Voice serial number, the key value used to index voice in the background, String
            'Size': size,  # Voice data size, Number 
            'Second': second  # Speech duration, unit: second Number 
        }
        super(SoundMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = uuid

    def set_size(self, size):
        self.size = size
        self.msgcontent['Size'] = size

    def set_second(self, second):
        self.second = second
        self.msgcontent['Second'] = second


class ImageMsg(MsgDict):
    def __init__(self,
                 uuid='',
                 imgformat=0,
                 imginfo=[],
                 msgtype='TIMImageElem'):
        self.uuid = uuid
        self.imgformat = imgformat
        self.imginfo = imginfo
        content = {
            'UUID': uuid,  # Picture serial number, key value used to index voice in the background, String
            'ImageFormat':
            imgformat,  # Picture format, BMP=1, JPG=2, GIF=3, others = 0, Number 
            'ImageInfoArray':
            [t.info for t in imginfo]  # Original image, thumbnail or large image, download information, Array
        }
        super(ImageMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = uuid

    def set_format(self, imgformat):
        self.imgformat = imgformat
        self.msgcontent['ImageFormat'] = imgformat

    def append_info(self, info):
        # info is an instance of ImageInfo object
        self.imginfo.append(info)
        self.msgcontnet['ImageInfoArray'].append(info.info)

    def insert_info(self, index, info):
        self.imginfo.insert(index, info)
        self.msgcontent['ImageInfoArray'].insert(index, info.info)

    def del_info(self, index):
        del self.imginfo[index]
        del self.msgcontent['ImageInfoArray'][index]


class FileMsg(MsgDict):
    def __init__(self, uuid='', size=0, name='', msgtype='TIMFileElem'):
        self.uuid = uuid
        self.size = size
        self.name = name
        content = {
            'UUID': uuid,  # File serial number, key value used to index voice in the background, String
            'FileSize': size,  # File data size, Number 
            'FileName': name  # File name / path, String
        }
        super(FileMsg, self).__init__(msgtype=msgtype, msgcontent=content)

    def set_uuid(self, uuid):
        self.uuid = uuid
        self.msgcontent['UUID'] = UUID

    def set_size(self, size):
        self.size = size
        self.msgcontent['FileSize'] = size

    def set_name(self, name):
        self.name = name
        self.msgcontent['FileName'] = name


class ImageInfo(object):
    def __init__(self, itype=1, size=0, width=0, height=0, url=''):
        #Picture type, 1-Original, 2-large, 3-thumbnail, 0-other
        self.itype = itype
        # Picture data size, Number
        self.size = size
        # Picture width, Number
        self.width = width
        # Picture height, Number
        self.height = height
        # Picture download address, String
        self.url = url

    @property
    def info(self):
        return {
            'Type': self.itype,
            'Size': self.size,
            'Width': self.width,
            'Height': self.height,
            'URL': self.url
        }

    def set_type(self, itype):
        self.itype = itype

    def set_size(self, size):
        self.size = size

    def set_width(self, width):
        self.width = width

    def set_height(self, height):
        self.height = height

    def set_url(self, url):
        self.url = url
 Copy code

Go and try it! Relevant information

① More than 2000 Python e-books (both mainstream and classic books should be available)

② Python standard library materials (the most complete Chinese version)

③ Project source code (forty or fifty interesting and classic hand training projects and source code)

④ Videos on basic introduction to Python, crawler, web development and big data analysis (suitable for Xiaobai)

⑤ Python learning roadmap (bid farewell to non stream learning)

Posted by Straterra on Mon, 25 Oct 2021 00:47:52 -0700