类方法、静态方法、属性方法
1.概念
- @classmethod, @staticmethod和@property这三个装饰器的使用对象是在类中定义的函数。
- @staticmethod装饰器可把其装饰的方法变为一个静态方法;
不能访问实例变量和类变量的;
可以通过类名来调用这个方法。 - @classmethod装饰器可把其装饰的方法变为一个类方法;
类方法只能访问类变量(全局属性/静态字段),不能访问实例变量。 - @propertyd装饰器可把其装饰的方法变成一个属性方法(静态属性);
在属性方法里传参,具体用法 @属性方法名.setter
删除属性方法,具体用法 @属性方法名.deleter
https://www.cnblogs.com/wangyongsong/p/6750454.html
https://www.cnblogs.com/revo/p/7381101.html
2.@staticmethod和@classmethod区别?
@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢?
从它们的使用上来看:
@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
示例
- 静态方法@staticmethod:
静态方法,通过类直接调用,不需要创建对象,不会隐式传递self,没有必须用staticmethod的情况,可以理解未定义在类里的普通函数。
是一种普通函数,位于类定义的命名空间中,不会对任何实例类型进行操作。
类方法@classmethod: - 类方法,方法中的self是类本身,调用方法时传的值也必须是类的公有属性,就是说类方法只能操作类本身的公有字段。
常用于定义备选构造方法
class Dog(object):
food = "gutou"
age = "1"
def __init__(self, name):
self.NAME = name
@classmethod
def eat(self, age): #只能是类中的变量
# print(self.NAME)
print(age)
print(self.food)
@classmethod
def eat1(self, age): # 只能是类中的变量
# print(self.NAME)
age = "2"
self.food = "tang"
@staticmethod
def print_1():
print(Dog.food, Dog.age)
d = Dog("labuladuo")
d.eat(Dog.age) #通过对象调用
Dog.eat(Dog.age) #通过类调用
print("-----1-----")
d.eat1(Dog.age)
Dog.print_1()
print("--------2-------")
Dog.eat1(Dog.age)
Dog.print_1()
- 属性方法@property:
属性变为私有属性,加断言判断属性对错;
将一个类的函数定义成@property以后, 对象再去使用的时候(obj.name),根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。
在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现
把一个方法变成静态属性有什么好处?想要静态变量,为什么不直接定义成一个静态变量?
如果某个属性的值是一系列动作后才得到的结果(比如一些计算或者条件判断),所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以.
不能赋值,但是可以通过@proerty.setter装饰器再装饰一下,此时你需要写一个新方法, 对这个flight_status进行更改。@name.deleter修饰可以用于删除操作(del ***)
#1.
class Circle:
def __init__(self,radius): # 圆的半径radius
self.radius=radius
@property
def area(self):
return math.pi * self.radius**2 # 计算面积
@property
def perimeter(self):
return 2*math.pi*self.radius # 计算周长
c=Circle(10)
print(c.radius)
print(c.area) # 可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) # 同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''
#2.
class Foo:
def __init__(self,val):
self.__NAME=val # 将所有的数据属性都隐藏起来
@property
def name(self):
return self.__NAME # obj.name访问的是self.__NAME(这也是真实值的存放位置)
@name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError('%s must be str' %value)
self.__NAME=value # 通过类型检查后,将值value存放到真实的位置self.__NAME
@name.deleter
def name(self):
raise TypeError('Can not delete')
f = Foo('egon')
print(f.name)
f.name = '10' # 可以赋值
print(f.name) # 输出 10
f.name = 10 # 抛出异常'TypeError: 10 must be str'
del f.name # 抛出异常'TypeError: Can not delete'