一、Python 中类的高阶函数
__str__
函数,当print当前实例化对象的时候,会打印出该函数中的return的信息,相当于Java中的 toString 函数,也就是对象的描述信息的定义函数
class Student(): def __init__(self, name): self.name = name # 定义实例化对象的描述信息 def __str__(self): return 'Student[name={}]'.format(self.name) def breath(self): print('Student can breath') if __name__ == '__main__': stu = Student('子渊') print(stu) stu.breath() 复制代码
打印对象时,输出了对象的属性信息也就是在__str__函数中返回的内容
__getattr__
函数,当调用的属性或者方法不存在时,会返回返函数中定义的信息。
class Student(): def __init__(self, name): self.name = name def __str__(self): return 'Student[name={}]'.format(self.name) def __getattr__(self, property): print('{}不存在'.format(property)) def breath(self): print('Student can breath') if __name__ == '__main__': stu = Student('子渊') print(stu) stu.breath() stu.age 复制代码
__setattr__
函数,可以拦截当前类中不存在的属性或值,给不存在的属性设置属性值;在上面的 Student 类中增加函数
def __setattr__(self, key, value): if key not in self.__dict__: self.__dict__[key] = value print('key={}, value={}'.format(key, value)) 复制代码
在main函数下增加代码
stu.like = 'lilith' stu.like 复制代码
__call__
函数可以将类变成一个函数;Student 类下增加函数
def __call__(self,name): print(name) 复制代码
在main函数中增加代码
# 像函数一样调用 stu('stark') 复制代码
实现链式调用
class Hero: def __init__(self, attr=''): self.__attr = attr def __getattr__(self, key): if self.__attr: key = '{}.{}'.format(self.__attr, key) else: key = key # 一定要返回Hero类才能实现链式调用 return Hero(key) def __call__(self, name): return name hero = Hero() name = hero.a.b.c('stark') print(name) 复制代码
二、装饰器
装饰器:
- 是一种函数
- 可以接受函数作为参数
- 可以返回函数
- 接收一个函数作为参数,内部对其进行处理,然后返回一个新函数,动态增强函数功能
定义一个装饰器
def out(func): # 外围函数 def inner(*args, **kwargs): # 内嵌函数,参数为外围函数参数的参数 return func(*args, **kwargs) return inner # 返回内嵌函数名,不加() 复制代码
装饰器的使用方式
- 将被调用的函数直接作为参数参入装饰器的外围函数的参数
- 将装饰器与被调用函数绑定在一起
- @符号+装饰器函数放在被调用函数的上一行,被调用的函数正常定义,只需要直接调用被执行函数即可
def output_log(func): # 定义内嵌函数,用来指定传入的函数,内嵌函数的参数为传入的函数的参数 def inner(*args, **kwargs): print('[info]{}被调用'.format(func.__name__)) res = func(*args, **kwargs) print('[info]{}返回的结果为:{}'.format(func.__name__, res)) return res # 返回内嵌函数的函数名 return inner # 使用装饰器 @output_log def alpha(data): return data res = alpha('pc12138') print(res) 复制代码
使用关键字传参和位置传参,并在装饰器中打印出传入的参数
def output_log(func): # 定义内嵌函数,用来指定传入的函数,内嵌函数的参数为传入的函数的参数 def inner(*args, **kwargs): print('[info]{}被调用'.format(func.__name__)) print('[info]{}传入的元组类型参数为{}'.format(func.__name__, args)) print('[info]{}传入的字典类型参数为{}'.format(func.__name__, kwargs)) res = func(*args, **kwargs) print('[info]{}返回的结果为:{}---------'.format(func.__name__, res)) return res # 返回内嵌函数的函数名 return inner # 使用装饰器 @output_log def alpha(data): return data alpha(data='pc12138') alpha('pc12138') 复制代码
类中的常用装饰器
@classmethod 装饰器
使用 @classmethod
装饰器标注的函数可以不经过实例化而直接使用类调用
@classmethod def func(cls, args): do 复制代码
cls
表示当前类本身,替代普通类函数中的self,self是指类实例化后的对象本身
class Bravo(): def __init__(self, x): self.x = x def walk(self): print('普通成员函数,需要实例化对象调用') @classmethod def run(cls): print('类直接调用的函数,无须实例化') Bravo.run() 复制代码
@classmethod
标注的函数可以通过类直接调用时
# 其他代码保持不变 @classmethod def run(cls): print('类直接调用的函数,无须实例化') cls.walk() 复制代码
@classmethod
标注的函数中无法调用普通的类的成员函数
class Bravo(): def __init__(self, x): self.x = x def walk(self): print('普通成员函数,需要实例化对象调用') self.run() @classmethod def run(cls): print('类直接调用的函数,无须实例化') # cls.walk() Bravo.run() bravo = Bravo('bravo') bravo.walk() 复制代码
普通类的成员函数中可以调用 @classmethod
标注的函数
# 其他代码保持不变 # 实例化对象直接调用 bravo.run() 复制代码
实例化对象可以调用普通的类成员函数也可以调用 @classmethod
标注的函数
@staticmethod 装饰器
@staticmethod
可以将类函数可以不经过实例化而直接被调用,被装饰器调用的函数无须传递 self 或者 cls 函数,且无法在该函数内调用其他类函数或者类变量
class Bravo(): def __init__(self, x): self.x = x def walk(self): print('普通成员函数,需要实例化对象调用') self.run() @staticmethod def run(): print('类直接调用的函数,无须实例化,且无须传入cls或者self参数') # self.wakl() # @classmethod # def rush(cls): # print() Bravo.run() bravo = Bravo('bravo') bravo.walk() bravo.run() 复制代码
类和普通对象以及类的普通函数中都可以调用 @staticmethod
标注的函数
@staticmethod def run(): print('类直接调用的函数,无须实例化') self.walk() 复制代码
@staticmethod
标注的函数中不能调用类的普通函数
增加一个 @classmethod
标注的函数
@classmethod def rush(cls): print('类直接调用的函数,无须实例化,需要传入cls参数') cls.run() 复制代码
@classmethod
标注的函数中可以调用 @staticmethod
标注的函数
@staticmethod def run(): print('类直接调用的函数,无须实例化,且无须传入cls或者self参数') self.rush() 复制代码
@staticmethod
标注的函数中无法调用 @classmethod
标注的函数
- 类的普通函数中既可以调用@staticmethod标注的函数也可以调用@classmethod标注的函数,因为含有self参数
- @classmethod标注的函数中可以调用@staticmethod标注的函数,因为有cls参数,但是不能调用普通类的函数,因为需要实例化
- @staticmethod标注的函数不可以调用@staticmethod标注的函数和类的普通函数,因为没有参数
@property 装饰器
@property
可以将类函数的执行免去括弧,类似于调用属性的方式
class Bravo(): def __init__(self, x): self.x = x def walk(self): print('普通成员函数,需要实例化对象调用') @property def run(self): print('类似于普通类函数,需要传入self参数,不同的是调用时不必加括弧') bravo = Bravo('bravo') bravo.run 复制代码
带有参数的 @property
标注的函数
class Bravo(): # 其余代码不变 @property def rush(self): return '带参数的@property函数要通过@函数名.setter设置参数,传入的参数为{}'.format(self.__name) # rush函数参数设置方式 @rush.setter def rush(self, name): self.__name = name bravo = Bravo('bravo') bravo.rush = 'Stark' res = bravo.rush print(res) 复制代码
@property
标注的函数如果有参数,要通过 @函数名.setter
来设置参数