property、classmethod和staticmethod、abstractmethod

在学习Deoldify的相关知识过程中,发现作者使用了非常多的类方法工具,因此在本文对常见的三种类修饰方法予以总结。

首先总结一下常见的python定义函数:

一般常见的是通过def定义的普通的一般的,需要至少传递一个参数,一般用self,这样的方法必须通过一个类的实例去访问,类似于c++中通过对象去访问;

一是在def前面加上@classmethod,这种类方法的一个特点就是可以通过类名去调用,但是也必须传递一个参数,一般用cls表示class,表示可以通过类直接调用;cls表示这个类本身。

二是在def前面加上@staticmethod,这种类方法是静态的类方法,类似于c++的静态函数,他的一个特点是参数可以为空,同样支持类名和对象两种调用方式,就可以无视这个self,将这个方法当成一个普通的函数使用。

三是在def前面加上@property,这种类方法是封装类中的方法,给用户更加简单的调用方式,隐藏具体的实现细节。简而言之就是可以在调用的时候不用加(),不细看无法发现其是函数的本质。

@property 属性方法

属性方法的作用就是通过 @property 把一个方法变成一个静态属性.

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

    def func(self):
        print("%s:基本方法" %self.name)

    @property  # pro = property(pro)
    def pro(self):
        print("%s:属性方法" %self.name)

foo_obj = Foo("alex")
foo_obj.func()
foo_obj.pro

一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。
既然 @staticmethod @classmethod 都可以直接类名.方法名()来调用,那他们有什么区别呢?从它们的使用上来看:

@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用类外部定义的函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数

@staticmethod

可以看成是静态方法,相当于已经脱离了这个类,是一个完全独立的函数。只是调用的时候必须通过这个类,或者为了规范代码而将函数放到类中,可以理解为类似于C++中的命名空间。
同时要注意的是静态方法在使用时因为没有self/cls参数的传入,是不能调用类内部其他方法的。

import time

class Date(object):
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    @staticmethod
    def now():
        t = time.localtime()
        return Date(t.tm_year, t.tm_mon, t.tm_mday)

date = Date.now()
print(date.year, date.month, date.day)

date = Date(1999,12,12)
@classmethod

类方法只能访问类变量,不能访问实例变量, 也就是跟类有关,跟实例无关,调用的时候只能写作:类名.方法名();实例.方法名()的方式是严格禁止的。

class ParentClass(object):
    var = "test for parent"

    @classmethod
    def clsmethod(cls):
        print(cls.var)

class SubClass(ParentClass):
    var = "test for sub"

ParentClass.clsmethod()
>>>
test for parent

SubClass.clsmethod()
>>>
test for sub

此时ParentClass.clsmethod输出为 “test for parent”,而Subclass.clsmethod输出为“test for sub”。通过此比较很好的诠释了@classmethod类方法隐式传入的第一个参数是当前类,而不是父类。同时类方法操作的是class 类对象提供的内部信息,而staticmethod可以作为一般的工具函数来使用。

总结:

Classmethod主要用途是作为构造函数;
Python只有一个构造函数__new__,如果想要多种构造函数就很不方便。只能在new里面写一堆if isinstance 。有classmethod之后就可以用classmethod来写不同的构造函数,cpython里面大部分classmethod最后都是 return cls(XXX), return XXX.new ()之类的。
Staticmethod主要用途是限定Namespace;也就是说这个函数虽然是个普通的function,但是它只有这个class会用到,不适合作为module level的function,这时候就把它作为staticmethod。如果不考虑namespace的问题的话直接在module里面def function就行了。

抽象类子类实例化

TypeError Cannot instantiate abstract class xxx with abstract method

问题描述:

使用metaclass=ABCMeta定义一个抽象类(由于python 没有抽象类、接口的概念,所以要实现这种功能得abc.py 这个类库),并在抽象类中声明几个抽象方法(@abstractmethod)或静态方法(@staticmethod)。

原因:抽象类的实例要重写抽象类的所有抽象方法,才能生成实例;相当于C++中的纯虚函数,大家都要重写

解决方法:子类中实现抽象方法。该问题是在解决上色算法的filter函数重写与分离过程中发现并解决的问题。如下代码片段所示,任意继承IFilter的函数方法都需要重写filter方法。

class IFilter(ABC):
    @abstractmethod
    def filter(
        self, orig_image: PilImage, filtered_image: PilImage, render_factor: int
    ) -> PilImage:
        pass
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值