python@staticmethod@classmethod@property介绍与使用

Python面向对象编程中,类中定义的方法可以是 @classmethod 装饰的类方法,也可以是 @staticmethod 装饰的静态方法,用的最多的还是不带装饰器的实例方法。那我们该如何区分使用它们呢?

介绍

class A(object):
    def m1(self, n):
        print("self:", self)

    @classmethod
    def m2(cls, n):
        print("cls:", cls)

    @staticmethod
    def m3(n):
        print('111')

a = A()
a.m1(1) # self: <__main__.A object at 0x000001E596E41A90>
A.m2(1) # cls: <class '__main__.A'>
A.m3(1) # 111

类中共定义了3个方法,m1 是实例方法,第一个参数必须是 self(约定俗成的)。m2 是类方法,第一个参数必须是cls(同样是约定俗成),m3 是静态方法,参数根据业务需求定,可有可无。

实例方法self

print(A.m1)
# A.m1在py2中显示为<unbound method A.m1>
<function A.m1 at 0x000002BF7FF9A488>

print(a.m1)
<bound method A.m1 of <__main__.A object at 0x000002BF7FFA2BE0>>

A.m1是一个还没有绑定实例对象的方法,对于未绑定方法,调用 A.m1 时必须显示地传入一个实例对象进去,而 a.m1是已经绑定了实例的方法,python隐式地把对象传递给了self参数,所以不再手动传递参数,这是调用实例方法的过程。

A.m1(a, 1)
# 等价  
a.m1(1)

类方法classmethod

print(A.m2)
<bound method A.m2 of <class '__main__.A'>>

print(a.m2)
<bound method A.m2 of <class '__main__.A'>>

m2是类方法,不管是 A.m2 还是 a.m2,都是已经自动绑定了类对象A的方法,对于后者,因为python可以通过实例对象a找到它所属的类是A,找到A之后自动绑定到 cls。

A.m2(1) 
 # 等价
a.m2(1)

这使得我们可以在实例方法中通过使用 self.m2()这种方式来调用类方法和静态方法。

def m1(self, n):
    print("self:", self)
    self.m2(n)

静态方法staticmethod

print(A.m3)
<function A.m3 at 0x000002BF7FF9A840>

print(a.m3)
<function A.m3 at 0x000002BF7FF9A840>

m3是类里面的一个静态方法,跟普通函数没什么区别,与类和实例都没有所谓的绑定关系,它只不过是碰巧存在类中的一个函数而已。不论是通过类还是实例都可以引用该方法。

A.m3(1) 
 # 等价
a.m3(1)

使用场景

1. @staticmethod

staticmethod用于修饰类中的方法,使其可以在不创建类实例的情况下调用方法,这样做的好处是执行效率比较高。当然,也可以像一般的方法一样用实例调用该方法。该方法一般被称为静态方法。静态方法不可以引用类中的属性或方法,其参数列表也不需要约定的默认参数self。我个人觉得,静态方法就是类对外部函数的封装,有助于优化代码结构和提高程序的可读性。当然了,被封装的方法应该尽可能的和封装它的类的功能相匹配。 这里给出一个样例来直观的说明一下其用法:

class Time():
    def __init__(self,sec):
        self.sec = sec
    #声明一个静态方法
    @staticmethod
    def sec_minutes(s1,s2):
        #返回两个时间差
        return abs(s1-s2)

t = Time(10)
#分别使用类名调用和使用实例调用静态方法
print(Time.sec_minutes(10,5),t.sec_minutes(t.sec,5))
#结果为5 5

2. @classmethod

classmethod好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符 @classmethod 就可以

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ...

当不使用@classmethod时处理字符串格式问题

class DateMethodBefore:
    def __init__(self,year=0,month=0,day=0):
        self.day=day
        self.month=month
        self.year=year

    def print_date(self):
        print(self.year)
        print(self.month)
        print(self.day)

# 对输入的字符串做处理输出
string_date = '2022-01-01'
year, month, day = map(int, string_date.split('-'))
dd = DateMethodBefore(year, month, day)
dd.print_date()
# 2022
# 1
# 1

当使用@classmethod时处理字符串格式问题

class DateMethodAfter:
    def __init__(self, year=0, month=0, day=0):
        self.day = day
        self.month = month
        self.year = year

    @classmethod
    def deal_date(cls, string_date):
        year, month, day = map(int, string_date.split('-'))
        date1 = cls(year, month, day)
        # 返回的是一个初始化后的class
        return date1

    def print_date(self):
        print(self.year)
        print(self.month)
        print(self.day)

dd = DateMethodAfter.deal_date("2022-01-01")
dd.print_date()
# 2022
# 1
# 1

@classmethod在继承时更好用。类方法的一个主要用途就是定义多个构造器:在已经写好初始类的情况下,想给初始类再新添功能,不需要修改初始类,只要在下一个类内部新写一个方法,使用@classmethod装饰一个即可。

# 初始类
class Date:
    def __init__(self, year=0, month=0, day=0):
        self.day = day
        self.month = month
        self.year = year

    def print_date(self):
        print(self.day)
        print(self.month)
        print(self.year)

# 新增功能
class Preprocess(Date):
    @classmethod
    def handle_date(cls, string_date):
        # 第一个参数cls,表示调用当前的类名
        year, month, day = map(int, string_date.split('-'))
        after_date = cls(year, month, day)
        # 返回一个初始化后的类
        return after_date

S = Preprocess.handle_date("2022-1-1")
S.print_date()

# 初始类Date不需要改变,新增功能handle_date;在Preprocess类里修改即可,Preprocess继承Date初始类

3. @property

可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改

使用场景1:

修饰方法,使func可以像属性一样访问

class DataSet(object):
    @property
    def method_with_property(self):  # 含有@property
        return 15
    def method_without_property(self):  # 不含@property
        return 15

l = DataSet()
print(l.method_with_property)  # 15
print(l.method_without_property())  # 15
# 加@property,可以用调用属性的方式来调用方法,后面不需要加()
# 没加@property , 必须使用正常的调用方法的形式,即在后面加()

如果使用property进行修饰后,又在调用的时候,方法后面添加了(), 那么就会显示错误信息:TypeError: ‘int’ object is not callable,也就是说添加@property 后,这个方法就变成了一个属性,如果后面加入了(),那么就是当作函数来调用,而它却不是callable(可调用)的。

使用场景2:

与所定义的属性配合使用,这样可以防止属性被修改
由于python进行属性定义时,没办法设置私有属性,因此要通过@property的方法来进行设置。这样可以隐藏属性名,让用户进行使用的时候无法随意修改。

class DataSet(object):
    def __init__(self):
        self._images = 1
        self._labels = 2 #定义属性的名称
    @property
    def images(self): #方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户有没办法随意修改。
        return self._images 
    @property
    def labels(self):
        return self._labels
l = DataSet()
#用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属性,从而保护了类的属性。
print(l.images) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。

参考连接:
https://zhuanlan.zhihu.com/p/28010894
https://blog.csdn.net/Liquor6/article/details/122440364
https://zhuanlan.zhihu.com/p/64487092
https://blog.sciencenet.cn/blog-3428464-1257579.html
https://cloud.tencent.com/developer/article/1597015

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WPF MVVM 是一种先进的开发模式,它通过数据绑定和命令绑定将视图与逻辑分离,以达到可重用性、可维护性、可扩展性和可测试性的目的。在一个完整的 WPF MVVM 项目中,通常会包含以下几个方面的内容: 1. 视图层(View): 视图层负责呈现数据和用户交互,它是 WPF 中的 XAML 文件。在 MVVM 中,视图层只负责呈现数据和相关的事件响应,把控制逻辑和业务逻辑交给ViewModel层。 2. 布局管理器(Layout Manager): 布局管理器负责管理视图的布局,根据不同的分辨率和屏幕大小,自动调整布局。这样可以使应用程序更具自适应性和兼容性。 3. ViewModel层: ViewModel层是MVVM模式的核心,它是一个中介层,负责逻辑处理和与视图层和数据层之间的数据交换。ViewModel层会包括各种命令(Command)、属性(Propetry)和数据(Data) 三大类数据模型,提供数据绑定和命令绑定等实现,将视图和模型解耦,将业务逻辑和控制逻辑分离。 4. 数据层(Data Access Layer): 数据层是负责数据读写的部分,包括数据访问对象(DAO)、数据模型(Model)和数据操作(Data Access Object),从而实现数据的存储、读取和更新。 5. 服务层(Service Layer): 服务层包括一些系统服务和第三方服务,例如网络服务、邮件服务、文件服务等。通过服务层,应用程序可以实现与其它系统或者接口的交互,提高系统的扩展性和可维护性。 总之,WPF MVVM项目是将各个层面保持独立的整个项目结构和流程化之后的一种方案的实现。它极大的提高了开发效率和代码的可重用性和维护性,适用于各种规模的项目或者团队,将其应用在项目中更有助于提升软件开发的质量和效果。 ### 回答2: WPF MVVM是一种在WPF项目中使用的最佳架构模式。一份完整的WPF MVVM项目应当包括以下几个方面: 1. 项目架构与设计 项目架构与设计应当有良好的规划与设计,应该包括一个正式的软件需求文档,以及包含系统模块和代码库的详细项目文档、代码注释和设计文档。 2. 数据库设计 项目应该定义数据库结构,并包含实现该结构的示例数据。 3. 代码实现框架 WPF MVVM 项目应该包含一个完整的框架,使得团队可以轻松地编写项目所需的代码。该框架应该包括一个基础架构的模块,以及UI界面模块、数据访问模块、数据模型模块等模块。 4. 文件组织 项目文件应该进行良好的组织和管理。所有的代码应该按照模块进行分类,并将其存放在相应的文件夹下。例如,可以将“ViewModels”文件夹放置于“Views”文件夹下面,将“Services”和“Repository”文件夹放置于根目录下。 5. 测试 在WPF MVVM项目中,测试是至关重要的。项目需包括一份详细的测试计划,以及一些工具来编写单元测试。 总之,一个完整的WPF MVVM项目包括架构和设计、数据库设计、代码实现框架、文件组织和测试,可以提高项目的质量、效率与开发速度。 ### 回答3: WPF MVVM 是一种现代化的软件开发模式,它借助于WPF(Windows Presentation Foundation)技术,实现了界面与业务逻辑的分离,大大提高了程序的可维护性和可扩展性,并且使我们可以更好的实现测试驱动开发和重用代码。 一个完整的WPF MVVM项目通常包含有以下几个方面的内容: 1. 数据源:数据源即应用程序需要使用的数据,可以是本地数据,也可以是远程服务器提供的数据。在开发过程中,我们需要通过合适的方式将数据导入我们的应用程序中,并对其进行处理。 2. ViewModel:ViewModel 是连接视图和模型的桥梁,它包含有从模型中获取数据的方法,并将数据转换成视图可以理解并显示的格式。同时ViewModel还提供了应用程序内部交互的命令和事件。 3. 视图:视图即我们的UI(用户界面),这里我们可以使用XAML定义我们的UI,当然也可以选择在代码中手动创建UI。视图可以通过数据绑定和命令绑定与ViewModel 进行交互。 4. 业务逻辑:业务逻辑是指应用程序中的数据操作和处理规则,例如验证用户输入、计算数据、存储数据等。 5. 单元测试:完成以上步骤之后,我们需要编写单元测试来验证每个组件是否都在正确运行,并且不会影响其他组件的正常操作。 在实现一个完整的WPF MVVM项目的时候,我们需要注意代码的可维护性和可扩展性,并且我们需要遵循MVVM模式的规则,将视图和业务逻辑分离,在视图和ViewModel之间建立良好的绑定关系。这样我们才能够完成高效顺畅的开发,并且在维护项目时也会更加方便快捷。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值