• Python入门示例系列38 面向对象(高级)


    实例⽅法
        定义:第⼀个参数必须是实例对象,该参数名⼀般约定为“self”,通过它来传递实例的属性和⽅法(也可以传类的属性和⽅法);
        调⽤:只能由实例对象调⽤。
    类⽅法
        定义:使⽤装饰器@classmethod。第⼀个参数必须是当前类对象,该参数名⼀般约定为“cls”,通过它来传递类的属性和⽅法(不能传实例的属性和⽅法);
        调⽤:实例对象类对象都可以调⽤。
    静态⽅法
        定义:使⽤装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是⽅法体中不能使⽤类或实例的任何属性和⽅法;
        调⽤:实例对象类对象都可以调⽤。

    实例方法,静态方法,类方法 的比较

    class Foo:
        """类三种方法语法形式"""
    
        def instance_method(self):
            print("是类{}的实例方法,只能被实例对象调用".format(Foo))
    
        @staticmethod
        def static_method():
            print("是静态方法")
    
        @classmethod
        def class_method(cls):
            print("是类方法")
    
    foo = Foo()
    foo.instance_method()
    foo.static_method()
    foo.class_method()
    print('----------------')
    Foo.static_method()
    Foo.class_method()

    说明:

    实例方法只能被实例对象调用(Python3 中,如果类调用实例方法,需要显示的传self, 也就是实例对象自己)。

    静态方法(由@staticmethod装饰的方法)、类方法(由@classmethod装饰的方法),可以被类或类的实例对象调用。
    实例方法,第一个参数必须要默认传实例对象,一般习惯用self。
    静态方法,参数没有要求。
    类方法,第一个参数必须要默认传类,一般习惯用cls。

    类方法用在模拟java定义多个构造函数的情况。 由于Python类中只能有一个初始化方法,不能按照不同的情况初始化类。

    class Book(object):
    
        def __init__(self, title):
            self.title = title
    
        @classmethod
        def create(cls, title):
            book = cls(title=title)
            return book
    
    book1 = Book("python")
    book2 = Book.create("python and django")
    print(book1.title)
    print(book2.title)

    静态方法也可以实现上面功能,但静态方法每次都要写上类的名字,不方便。

    @classmethod 示例:

    class A(object):
    
        # 属性默认为类属性(可以给直接被类本身调用)
        num = "类属性"
    
        # 实例化方法(必须实例化类之后才能被调用)
        def func1(self): # self : 表示实例化类后的地址id
            print("func1")
            print(self)
    
        # 类方法(不需要实例化类就可以被类本身调用)
        @classmethod
        def func2(cls):  # cls : 表示没用被实例化的类本身
            print("func2")
            print(cls)
            print(cls.num)
            cls().func1()
    
        # 不传递传递默认self参数的方法(该方法也是可以直接被类调用的,但是这样做不标准)
        def func3():
            print("func3")
            print(A.num) # 属性是可以直接用类本身调用的
        
    # A.func1() 这样调用是会报错:因为func1()调用时需要默认传递实例化类后的地址id参数,如果不实例化类是无法调用的
    A.func2()
    A.func3()

    输出结果为:

    func2
    1
    foo

    看下面的定义的一个时间类: 

    class Data_test(object):
        day=0
        month=0
        year=0
        def __init__(self,year=0,month=0,day=0):
            self.day=day
            self.month=month
            self.year=year
     
        def out_date(self):
            print "year :"
            print self.year
            print "month :"
            print self.month
            print "day :"
            print self.day
     
    t=Data_test(2016,8,1)
    t.out_date()

    输出:

    year :
    2016
    month :
    8
    day :
    1

     
    符合期望。
     
    如果用户输入的是 "2016-8-1" 这样的字符格式,那么就需要调用Date_test 类前做一下处理: 

    string_date='2016-8-1'
    year,month,day=map(int,string_date.split('-'))
    s=Data_test(year,month,day)

     
    先把‘2016-8-1’ 分解成 year,month,day 三个变量,然后转成int,再调用Date_test(year,month,day)函数。 也很符合期望。
     
    那我可不可以把这个字符串处理的函数放到 Date_test 类当中呢?
     
    那么@classmethod 就开始出场了
     

    class Data_test2(object):
        day=0
        month=0
        year=0
        def __init__(self,year=0,month=0,day=0):
            self.day=day
            self.month=month
            self.year=year
     
        @classmethod
        def get_date(cls,data_as_string):
            #这里第一个参数是cls, 表示调用当前的类名
            year,month,day=map(int,string_date.split('-'))
            date1=cls(year,month,day)
            #返回的是一个初始化后的类
            return date1
     
        def out_date(self):
            print "year :"
            print self.year
            print "month :"
            print self.month
            print "day :"
            print self.day

     
    在Date_test类里面创建一个成员函数, 前面用了@classmethod装饰。 它的作用就是有点像静态类,比静态类不一样的就是它可以传进来一个当前类作为第一个参数。
     
    那么如何调用呢? 

    r=Data_test2.get_date("2016-8-6")
    r.out_date()

    输出:

    year :
    2016
    month :
    8
    day :
    1


     
    这样子等于先调用get_date()对字符串进行出来,然后才使用Data_test的构造函数初始化。
     
    这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符 @classmethod 就可以了。

    REF:

    https://www.jb51.net/article/168278.htm

    https://www.cnblogs.com/baxianhua/p/10845620.html

    https://zhuanlan.zhihu.com/p/21101992

    https://wenku.baidu.com/view/5c2c4a9b8462caaedd3383c4bb4cf7ec4afeb693.html

    https://baijiahao.baidu.com/s?id=1700147092491716904&wfr=spider&for=pc

    https://www.cnblogs.com/baxianhua/p/10845620.html

    https://www.runoob.com/python/python-func-classmethod.html

  • 相关阅读:
    字节码插桩技术
    排序算法
    oracle创建简单存储过程示例
    tomcat短连接与长连接的配置
    从linux到zookeeper
    拱卒人生
    集合运算
    读取properties
    oracle的那些事
    WebService
  • 原文地址:https://www.cnblogs.com/emanlee/p/15820468.html
Copyright © 2020-2023  润新知