一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
一、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函数下增加代码
代码语言:javascript复制stu.like = 'lilith'
stu.like
__call__
函数可以将类变成一个函数;Student 类下增加函数
def __call__(self,name):
print(name)
在main函数中增加代码
代码语言:javascript复制# 像函数一样调用
stu('stark')
实现链式调用
代码语言:javascript复制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)
二、装饰器
装饰器:
- 是一种函数
- 可以接受函数作为参数
- 可以返回函数
- 接收一个函数作为参数,内部对其进行处理,然后返回一个新函数,动态增强函数功能
定义一个装饰器
代码语言:javascript复制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)
使用关键字传参和位置传参,并在装饰器中打印出传入的参数
代码语言:javascript复制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
来设置参数