• python 类中方法总结 --- 实例方法、类方法、静态方法


    在python的类语法中,可以出现三种方法,具体如下:

    (1)实例方法

    很多人学习python,不知道从何学起。
    很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
    很多已经做案例的人,却不知道如何去学习更加高深的知识。
    那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
    QQ群:1097524789

    1)第一个参数必须是实例本身,一般使用【self】表示。

    2)在实例方法中,可以通过【self】来操作实例属性,【类名】来操作类属性。

    3)实例方法只能通过实例对象去调用,尽管也可以通过类名间接调用【类名.方法名(self, ...)】,但此时仍然需要传入self对象。

    (2)类方法

    1)使用【@classmethod】修饰函数,且第一个参数必须是类本身,一般使用【cls】表示。

    2)在类方法中,可以使用【cls=类名】来操作类属性,但是不能操作实例属性(self对象中存储的变量)。

    3)类方法可以通过实例对象或者类对象调用。

    (3)静态方法

    1)使用【@staticmethod】修饰函数,不需要使用任何参数表示。与普通函数一样,只是将该方法放到了类中实现而已。

    2)使用方式与类方法一样,参考类方法中的 2)、3)。(注:静态方法只能通过【类名】去操作类属性;)

    案例1:实例方法、类方法、静态方法使用

    class Foo(object):
        """类三种方法语法形式"""
        count = 0   # 统计实例对象的数量
        class_method_count = 0  # 统计类方法的调用次数
    
        # 实例方法
        def __init__(self, name):
            self.name = name
            Foo.count += 1
    
        # 实例方法
        def instance_method(self):
            print("是类{}的实例方法,只能被实例对象调用".format(Foo))
            print("产生了一个<{}>实例,共有<{}>个实例对象".format(self.name, Foo.count))
    
        # 类方法
        @classmethod
        def class_method(cls):
            print("是类{}的类方法,可以被实例对象、类对象调用".format(cls))
            cls.__static_method_test()
            cls.class_method_count += 1
    
        # 静态方法
        @staticmethod
        def static_method():
            print("是类{}的静态方法,可以被实例对象、类对象调用".format(Foo))
            print("+++以下内容为类方法class_method()的运行结果:")
            Foo.class_method()
    
        @staticmethod
        def __static_method_test():
            print("调用了静态方法 static_method_test()")
    
    print("--"*20 + "实例方法测试" + "--"*20)
    obj1 = Foo("dog")
    obj1.instance_method()   # <=> Foo.instance_method(obj1)
    
    
    print("--"*20 + "类方法测试" + "--"*20)
    obj1.class_method()
    print("--"*20)
    Foo.class_method()
    
    print("--"*20 + "静态方法测试" + "--" * 20)
    obj1.static_method()
    print("--"*20)
    Foo.static_method()
    
    """
    运行结果:
    ----------------------------------------实例方法测试----------------------------------------
    是类<class '__main__.Foo'>的实例方法,只能被实例对象调用
    产生了一个<dog>实例,共有<1>个实例对象
    ----------------------------------------类方法测试----------------------------------------
    是类<class '__main__.Foo'>的类方法,可以被实例对象、类对象调用
    调用了静态方法 static_method_test()
    ----------------------------------------
    是类<class '__main__.Foo'>的类方法,可以被实例对象、类对象调用
    调用了静态方法 static_method_test()
    ----------------------------------------静态方法测试----------------------------------------
    是类<class '__main__.Foo'>的静态方法,可以被实例对象、类对象调用
    +++以下内容为类方法class_method()的运行结果:
    是类<class '__main__.Foo'>的类方法,可以被实例对象、类对象调用
    调用了静态方法 static_method_test()
    ----------------------------------------
    是类<class '__main__.Foo'>的静态方法,可以被实例对象、类对象调用
    +++以下内容为类方法class_method()的运行结果:
    是类<class '__main__.Foo'>的类方法,可以被实例对象、类对象调用
    调用了静态方法 static_method_test()
    """
    

    从案例1中得到,类方法与静态方法可以相互调用,但是静态方法只能用【类名】表示,而类方法用【cls】就比较方便了。

    案例2:实例方法、类方法、静态方法在继承中(子类重写父类中的方法)的使用

    class Foo(object):
        X = 1
        Y = 14
    
        @staticmethod
        def average(*mixes):
            print("父类中的静态方法 average(*mixes)")
            print("*****", mixes)
            return sum(mixes) / len(mixes)
    
        @staticmethod
        def static_method():
            print("父类中的静态方法 static_method()")
            return Foo.average(Foo.X, Foo.Y)    # 注:因为这儿已经限定了只允许调用父类中的average()
    
        @classmethod
        def class_method(cls):  # 父类中的类方法
            print("父类中的类方法 class_method(cls)")
            return cls.average(cls.X, cls.Y)    # 注:若用子类对象调用该函数,此时的cls==Son,故调用子类重写后的average()
    
    
    class Son(Foo):
        @staticmethod
        def average(*mixes):  # "子类中重载了父类的静态方法"
            print("子类中重载了父类的静态方法 average(*mixes)")
            print("*****", mixes)
            return sum(mixes) / len(mixes)
    
    print(Son.average(1, 2, 3), "
    " + "---" * 20)
    print(Son.class_method(),   "
    " + "---" * 20)
    print(Son.static_method(),  "
    " + "---" * 20)
    
    """
    运行结果:
    ------------------------------------------------------------
    子类中重载了父类的静态方法 average(*mixes)
    ***** (1, 2, 3)
    2.0 
    ------------------------------------------------------------
    父类中的类方法 class_method(cls)
    子类中重载了父类的静态方法 average(*mixes)
    ***** (1, 14)
    7.5 
    ------------------------------------------------------------
    父类中的静态方法 static_method()
    父类中的静态方法 average(*mixes)
    ***** (1, 14)
    7.5 
    ------------------------------------------------------------
    """
    

    从案例2中得到,子类对象调用父类中的 类方法 class_method(cls) 时,由于【cls】此时为【Son】,故会执行子类中的类方法、静态方法、静态属性;进一步推断出,类方法中【cls】取决于类方法的调用者,只有发生类方法调用后才能知道执行结果。而父类中静态方法 static_method()只能调用父类中类方法、静态方法、静态属性,与静态方法的调用者无关;进一步推断,静态方法可以提前预知程序的执行结果,如执行当前类中的某个类方法或静态方法。

    对案例2做一个多态测试,添加代码如下:

    def test_polymorphic(foo):
        """
        多态测试
        :param foo: 父类对象
        :return: None
        """
        print(f.average(1, 2, 3))
    
    f = Foo()
    test_polymorphic(f)
    
    print("----"*10)
    f = Son()  # 会触发多态
    test_polymorphic(f)
    
    """
    父类中的静态方法 average(*mixes)
    ***** (1, 2, 3)
    2.0
    ----------------------------------------
    子类中重载了父类的静态方法 average(*mixes)
    ***** (1, 2, 3)
    2.0
    """
    

    继续做多态测试,添加代码如下:

    def test_polymorphic(foo):
        """
        多态测试
        :param foo: 父类对象
        :return: None
        """
        print(f.class_method())
    
    f = Foo()
    test_polymorphic(f)
    
    print("----"*10)
    f = Son()  # 会触发多态
    test_polymorphic(f)
    
    """
    父类中的类方法 class_method(cls)
    父类中的静态方法 average(*mixes)
    ***** (1, 14)
    7.5
    ----------------------------------------
    父类中的类方法 class_method(cls)
    子类中重载了父类的静态方法 average(*mixes)
    ***** (1, 14)
    7.5
    """
    

    案例3:使用类方法或静态方法初始化类(可以自定义类的初始方式)

    class Book(object):
        def __init__(self, title):
            self.__title = title
    
        @classmethod
        def object_create_by_class_method(cls, title_list):
            """
            使用生产器实例化多个对象
            :param title_list: 每个对象的初始化参数,List
            :return:迭代器,每个实例化对象
            """
            for title in title_list:
                yield cls(title=title)
    
        @staticmethod
        def object_create_by_static_method(title_list): # 功能与类方法一样
            for title in title_list:
                yield Book(title=title)
    
        @property
        def title(self):
            return self.__title
    
        @title.setter
        def title(self, value):
            if not isinstance(value, str):
                raise TypeError('%s must be str' % value)
            self.__title = value
    
        @title.deleter
        def title(self):
            del self.__title
            # raise TypeError('Can not delete')
    
    
    books = ["Chinese", "mathematics", "English"]
    g_books = Book.object_create_by_class_method(books)
    print(g_books)  # <generator object Book.object_create_by_class_method at 0x000001FB72AFEEC8>
    
    print(g_books.__next__().title)     # 查看书的title  --   Chinese
    print(g_books.__next__().title)     # 查看书的title  --   mathematics
    
    book = g_books.__next__()   # 得到一个实例化对象
    
    print(book.title)           # 查看书的title  --   English
    print(book.__dict__)        # {'_Book__title': 'English'}
    
    book.title = "英语"          # 修改属性
    print(book.title)           # 查看书的title  --   英语
    print(book.__dict__)        # {'_Book__title': '英语'}
    
    del book.title              # 删除属性
    print(book.__dict__)        # {}
    

    从案例3中得到,使用类方法或者静态方法可以自定义类的初始化方式,本案例中实现的功能是使用生产器批量创建多个对象。同时,案列中使用了【property】属性,property的作用相当于执行了某个函数,并获得该函数的返回值;其使用方式有3种,分别为【@property --- get】、【@函数名.setter --- set】、【@函数名.deleter --- del】,后二种必须在第一种使用的情况下才能使用,在表现形式上就是通过实例化对象间接访问属性。

    最后,我们对案例3做微小改变,来看看实例方法、类方法、静态方法与类、对象之间的关系,代码如下:

    class Book(object):
        @classmethod
        def object_create_by_class_method(cls):
            pass
    
        @staticmethod
        def object_create_by_static_method():
            pass
    
        def instance_method(self):
            pass
    
    book = Book()
    print(book.instance_method)     # 方法(绑定到对象:发生调用时,将【实例对象=self】自动作为第一个参数传入实例方法中)
    print(book.object_create_by_class_method)   # 方法(绑定到类:发生调用时,将【类=cls】自动作为第一个参数传入类方法中)
    print(book.object_create_by_static_method)  # 普通函数(非绑定:发生调用时,不需要传入任何参数,如self,cls)
    
    print(Book.instance_method)     # 普通函数(非绑定,因为实例方法就存储在类的命名空间中)
    print(Book.object_create_by_class_method)   # 绑定到类
    print(Book.object_create_by_static_method)  # 普通函数(非绑定)
    """
    <bound method Book.instance_method of <__main__.Book object at 0x000002481CEDE988>>
    <bound method Book.object_create_by_class_method of <class '__main__.Book'>>
    <function Book.object_create_by_static_method at 0x000002481D12C828>
    
    <function Book.instance_method at 0x000002481D12C8B8>
    <bound method Book.object_create_by_class_method of <class '__main__.Book'>>
    <function Book.object_create_by_static_method at 0x000002481D12C828>
    """
    

    可以发现,

    1)类中的实例方法都绑定了实例对象,故建议使用实例对象调用实例方法;

    2)类中的类方法都绑定了类,故建议使用类对象调用类方法,即使使用实例对象调用类方法,仍然自动将【类名】作为第一个参数传入类方法。

    3)而对于静态方法而言,无论使用实例对象或者类对象调用其方法都不会自动进行参数传递,故不做限制。

    4)若能用类解决的问题,就将类中的方法定义为类方法,这样可以避免实例化对象的开销。

  • 相关阅读:
    php递归无限分类、根据子类获取所有顶类
    PHP+Redis 有序集合实现 24 小时排行榜实时更新
    php操作redis常用方法代码示例
    Mysql 数据库默认值选 ''" 、Null和Empty String的区别
    linux查看端口占用情况
    php获取微信openid
    phpstorm 删除空行
    git常用操作命令归纳
    Redis数据类型
    渴求式加载指定字段、加载多个关联关系、嵌套的渴求式加载、带条件约束的渴求式加载
  • 原文地址:https://www.cnblogs.com/shann001/p/13219421.html
Copyright © 2020-2023  润新知