Python之特性、静态方法、类方法

本文深入解析Python中的特性(property),静态方法(staticmethod)及类方法(classmethod)的使用场景和原理,同时探讨__str__方法的应用,帮助理解Python面向对象编程的核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特性property

1:什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。

 1 import math
 2 class Circle:
 3     def __init__(self,radius): #圆的半径radius
 4         self.radius=radius
 5 
 6     @property
 7     def area(self):
 8         return math.pi * self.radius**2 #计算面积
 9 
10     @property
11     def perimeter(self):
12         return 2*math.pi*self.radius #计算周长
13 
14 c=Circle(10)
15 print(c.radius)
16 print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
17 print(c.perimeter) #同上
18 '''
19 输出结果:
20 314.1592653589793
21 62.83185307179586
22 '''

注意:此时的特性arear和perimeter不能被赋值

 

2: 为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。

python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现。

 1 class Foo:
 2     def __init__(self,val):
 3         self.__NAME=val #将所有的数据属性都隐藏起来
 4 
 5     @property
 6     def name(self):
 7         return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)
 8 
 9     @name.setter
10     def name(self,value):
11         if not isinstance(value,str):  #在设定值之前进行类型检查
12             raise TypeError('%s must be str' %value)
13         self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME
14 
15     @name.deleter
16     def name(self):
17         raise TypeError('Can not delete')
18 
19 f=Foo('egon')
20 print(f.name)
21 # f.name=10 #抛出异常'TypeError: 10 must be str'
22 del f.name #抛出异常'TypeError: Can not delete'

  通常情况下,在类中定义的所有函数(注意了,这里说的就是所有,跟self啥的没关系,self也只是一个再普通不过的参数而已)都是对象的绑定方法,对象在调用绑定方法时会自动将自己作为参数传递给方法的第一个参数。除此之外还有两种常见的方法:静态方法和类方法,二者是为类量身定制的,但是实例非要使用,也不会报错。

 

@staticmethod means: when this method is called, we don't pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can't access the instance of that class (this is useful when your method does not use the instance).

 

@classmethod means: when this method is called, we pass the class as the first argument instead of the instance of that class (as we normally do with methods). This means you can use the class and its properties inside that method rather than a particular instance.

 

 

静态方法(staticmethod)

是一种普通函数,位于类定义的命名空间中,不会对任何实例类型进行操作,python为我们内置了函数staticmethod来把类中的函数定义成静态方法。
class Foo:
    def spam(x,y,z): #类中的一个函数,千万不要懵逼,self和x啥的没有不同都是参数名
        print(x,y,z)
    spam=staticmethod(spam) #把spam函数做成静态方法
基于之前所学装饰器的知识,@staticmethod 等同于spam=staticmethod(spam),于是

class Foo:
    @staticmethod #装饰器
    def spam(x,y,z):
        print(x,y,z)
 1 print(type(Foo.spam)) #类型本质就是函数
 2 Foo.spam(1,2,3) #调用函数应该有几个参数就传几个参数
 3 
 4 f1=Foo()
 5 f1.spam(3,3,3) #实例也可以使用,但通常静态方法都是给类用的,实例在使用时丧失了自动传值的机制
 6 
 7 '''
 8 <class 'function'>
 9 3
10 3
11 '''

 应用场景:编写类时需要采用很多不同的方式来创建实例,而我们只有一个__init__函数,此时静态方法就派上用场了

 

 1 class Date:
 2     def __init__(self,year,month,day):
 3         self.year=year
 4         self.month=month
 5         self.day=day
 6     @staticmethod
 7     def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间
 8         t=time.localtime() #获取结构化的时间格式
 9         return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
10     @staticmethod
11     def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
12         t=time.localtime(time.time()+86400)
13         return Date(t.tm_year,t.tm_mon,t.tm_mday)
14 
15 a=Date('1987',11,27) #自己定义时间
16 b=Date.now() #采用当前时间
17 c=Date.tomorrow() #采用明天的时间
18 
19 print(a.year,a.month,a.day)
20 print(b.year,b.month,b.day)
21 print(c.year,c.month,c.day)

 

 

 

类方法(classmethod)         

类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python为我们内置了函数classmethod来把类中的函数定义成类方法。

 1 class A:
 2     x=1
 3     @classmethod
 4     def test(cls):
 5         print(cls,cls.x)
 6 
 7 class B(A):
 8     x=2
 9 B.test()
10 
11 '''
12 输出结果:
13 <class '__main__.B'> 2
14 '''
 1 import time
 2 class Date:
 3     def __init__(self,year,month,day):
 4         self.year=year
 5         self.month=month
 6         self.day=day
 7     @staticmethod
 8     def now():
 9         t=time.localtime()
10         return Date(t.tm_year,t.tm_mon,t.tm_mday)
11 
12 class EuroDate(Date):
13     def __str__(self):
14         return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
15 
16 e=EuroDate.now()
17 print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
18 '''
19 输出结果:
20 <__main__.Date object at 0x1013f9d68>
21 '''

 因为e就是用Date类产生的,所以根本不会触发EuroDate.__str__,解决方法就是用classmethod。

 

 1 import time
 2 class Date:
 3     def __init__(self,year,month,day):
 4         self.year=year
 5         self.month=month
 6         self.day=day
 7     # @staticmethod
 8     # def now():
 9     #     t=time.localtime()
10     #     return Date(t.tm_year,t.tm_mon,t.tm_mday)
11 
12     @classmethod #改成类方法
13     def now(cls):
14         t=time.localtime()
15         return cls(t.tm_year,t.tm_mon,t.tm_mday) #哪个类来调用,即用哪个类cls来实例化
16 
17 class EuroDate(Date):
18     def __str__(self):
19         return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)
20 
21 e=EuroDate.now()
22 print(e) #我们的意图是想触发EuroDate.__str__,此时e就是由EuroDate产生的,所以会如我们所愿
23 '''
24 输出结果:
25 year:2017 month:3 day:3
26 '''

强调,注意注意注意:静态方法和类方法虽然是给类准备的,但是如果实例去用,也是可以用的。

 

 

———————————————————————————————————————————

 

 

Though classmethod and staticmethod are quite similar, there's a slight difference in usage for both entities: classmethod must have a reference to a class object as the first parameter, whereas staticmethod can have no parameters at all.

 1 Example
 2 
 3 class Date(object):
 4 
 5     def __init__(self, day=0, month=0, year=0):
 6         self.day = day
 7         self.month = month
 8         self.year = year
 9 
10     @classmethod
11     def from_string(cls, date_as_string):
12         day, month, year = map(int, date_as_string.split('-'))
13         date1 = cls(day, month, year)
14         return date1
15 
16     @staticmethod
17     def is_date_valid(date_as_string):
18         day, month, year = map(int, date_as_string.split('-'))
19         return day <= 31 and month <= 12 and year <= 3999
20 
21 date2 = Date.from_string('11-09-2012')
22 is_date = Date.is_date_valid('11-09-2012')

 

Explanation

Let's assume an example of a class, dealing with date information (this is what will be our boilerplate to cook on):

1 class Date(object):
2 
3     def __init__(self, day=0, month=0, year=0):
4         self.day = day
5         self.month = month
6         self.year = year

 This class obviously could be used to store information about certain dates (without timezone information; let's assume all dates are presented in UTC).

Here we have __init__, a typical initializer of Python class instances, which receives arguments as a typical instancemethod, having the first non-optional argument (self) that holds reference to a newly created instance.

 

Class Method

We have some tasks that can be nicely done using classmethods.

Let's assume that we want to create a lot of Date class instances having date information coming from outer source encoded as a string of next format ('dd-mm-yyyy'). We have to do that in different places of our source code in project.

So what we must do here is:

  1. Parse a string to receive day, month and year as three integer variables or a 3-item tuple consisting of that variable.
  2. Instantiate Date by passing those values to initialization call.

This will look like:

day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)

 

For this purpose, C++ has such feature as overloading, but Python lacks that feature- so here's when classmethod applies. Lets create another "constructor"

1 @classmethod
2     def from_string(cls, date_as_string):
3         day, month, year = map(int, date_as_string.split('-'))
4         date1 = cls(day, month, year)
5         return date1
6 
7 date2 = Date.from_string('11-09-2012')

 Let's look more carefully at the above implementation, and review what advantages we have here:

  1. We've implemented date string parsing in one place and it's reusable now.
  2. Encapsulation works fine here (if you think that you could implement string parsing as a single function elsewhere, this solution fits OOP paradigm far better).
  3. cls is an object that holds class itself, not an instance of the class. It's pretty cool because if we inherit our Date class, all children will have from_string defined also.

 

 

Static method

What about staticmethod? It's pretty similar to classmethod but doesn't take any obligatory parameters (like a class method or instance method does).

Let's look at the next use case.

We have a date string that we want to validate somehow. This task is also logically bound to Dateclass we've used so far, but still doesn't require instantiation of it.

Here is where staticmethod can be useful. Let's look at the next piece of code:

1     @staticmethod
2     def is_date_valid(date_as_string):
3         day, month, year = map(int, date_as_string.split('-'))
4         return day <= 31 and month <= 12 and year <= 3999
5 
6     # usage:
7     is_date = Date.is_date_valid('11-09-2012')

 

So, as we can see from usage of staticmethod, we don't have any access to what the class is- it's basically just a function, called syntactically like a method, but without access to the object and it's internals (fields and another methods), while classmethod does.

 

 

本文来自于:

python基础----特性(property)、静态方法(staticmethod)、类方法(classmethod)、__str__的用法

知乎用户fosmjo

stackoverflow用户crizCraig

感谢!!!

 

转载于:https://www.cnblogs.com/wang2825/articles/8929889.html

<think>好的,我现在需要向用户介绍Python中的类方法静态方法。首先,我得回忆一下这两个概念的基本定义和区别。类方法静态方法都是Python中的装饰器,分别用@classmethod和@staticmethod来修饰。但它们的用途和参数有所不同。 类方法,我记得第一个参数是cls,代表类本身,而不是实例。这样类方法可以访问类的属性,甚至修改类的状态。比如,创建工厂方法,根据不同的参数生成类的实例。而静态方法没有这样的参数,它更像是一个普通函数,只是放在类的命名空间里,可能和类有逻辑上的关联,但不需要访问类或实例的数据。 然后,我需要想一些例子来说明两者的使用场景。比如,类方法可以用于创建替代构造函数,而静态方法可能处理一些与类相关但不需要类或实例参与的任务,比如输入验证或工具函数。 接下来,用户可能想知道如何正确使用它们,以及什么时候选择哪个。这时候需要强调参数的区别:类方法需要cls,静态方法不需要。另外,继承时的行为差异也很重要,类方法在子类中被调用时,cls会是子类,而静态方法则不会这样。 可能用户会混淆静态方法和实例方法,或者不知道何时使用静态方法。需要指出静态方法不需要访问实例或类,所以如果方法不需要self或cls,就可以考虑静态方法。 还需要检查是否有常见的错误或误解,比如误用静态方法代替类方法,或者在静态方法中尝试访问类变量,这样会导致错误,因为静态方法没有cls参数。 最后,要确保结构清晰,分点解释,给出示例代码,并比较两者的区别和适用场景。同时,要使用中文,避免术语混淆,保持口语化,但不过于随意。确保LaTeX格式正确,如果有数学表达式的话,但当前问题可能不需要数学公式,所以可能不需要用到。不过,按照用户给的系统指令,所有行内数学表达式需要用$...$,独立公式用$$...$$,但这个问题可能不涉及数学公式,所以可能需要忽略这部分,或者如果有变量名之类的,可以用$...$包裹。 总结步骤: 1. 定义类方法静态方法,语法和装饰器。 2. 参数区别:cls vs 无。 3. 用途和示例:类方法作为工厂方法,静态方法作为工具函数。 4. 继承中的行为差异。 5. 对比总结,何时使用哪种方法。 现在需要组织这些内容,确保结构清晰,符合用户要求的中文回答。</think>在Python面向对象编程中,类方法静态方法是两种常用的方法类型,它们通过装饰器定义,用途和特性有所不同。以下是逐步说明: --- ### 一、基本概念 1. **类方法(Class Method)** - **定义方式**:用 `@classmethod` 装饰器修饰 - **第一个参数**:必须为 `cls`(表示类本身) - **用途**:操作类级别的属性或创建工厂方法 - **示例**: ```python class MyClass: class_attr = 0 @classmethod def update_class_attr(cls, value): cls.class_attr = value # 直接修改类属性 ``` 2. **静态方法(Static Method)** - **定义方式**:用 `@staticmethod` 装饰器修饰 - **参数**:无需 `self` 或 `cls`(像一个普通函数) - **用途**:执行与类相关但无需访问类或实例的操作 - **示例**: ```python class MathUtils: @staticmethod def add(a, b): return a + b # 无需依赖类或实例 ``` --- ### 二、核心区别 | 特性 | 类方法 | 静态方法 | |---------------------|---------------------------|----------------------| | **参数** | 必须包含 `cls` | 无特殊参数 | | **访问类属性** | 可通过 `cls` 访问 | 不可直接访问 | | **继承行为** | 子类调用时 `cls` 为子类 | 与父类无关 | | **典型用途** | 工厂方法、类状态修改 | 工具函数、逻辑分组 | --- ### 三、使用场景示例 #### 场景1:类方法作为工厂方法 ```python class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day @classmethod def from_string(cls, date_str): year, month, day = map(int, date_str.split("-")) return cls(year, month, day) # 根据字符串创建实例 # 使用类方法创建对象 date = Date.from_string("2023-10-05") ``` #### 场景2:静态方法实现工具函数 ```python class StringHelper: @staticmethod def is_palindrome(s): return s == s[::-1] # 判断是否为回文 # 直接调用静态方法 print(StringHelper.is_palindrome("level")) # 输出 True ``` --- ### 四、如何选择? 1. **用类方法**: - 需要访问或修改类状态 - 需要实现基于不同参数的构造函数(工厂模式) 2. **用静态方法**: - 方法逻辑与类相关,但无需访问类或实例 - 代码组织需求(将相关函数分组到类中) --- ### 五、总结 - **类方法**通过 `cls` 绑定到类,适合操作类级别的属性和行为。 - **静态方法**独立于类和实例,适合纯粹的功能性函数。 - 两者都能通过类名直接调用(无需实例化),但设计目的不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值