9、反射
反射针对的是类、对象和模块
反射:通过字符串去操作类对象或者模块当中的成员(属性方法)
hasattr、getattr、setattr、delattr
(1)反射类、对象中的成员
hasattr:判断类或对象中是否存在指定的成员
注:判定的必须是字符串形式的成员
getattr:获取对象/类成员的值
注:通过类反射出来的是一个普通方法;通过对象反射出来的是绑定方法;
当类对象中的成员不存在时,可以设置默认值(第三个参数是默认值参数)
setattr:设置对象/类成员的值
delattr:删除对象/类成员的值
(2)反射模块中的成员
四个方法使用方式是和上面一样的
sys.moudles 返回一个系统的字典,加载系统模块展现出来
# (1)反射类、对象中的成员
class Man:
pass
class Woman:
pass
class Children(Man, Woman):
eye = "red eyes"
def skylight(self):
print("出生就会天照")
def moonread(self, func):
print("出生就会月读")
def __makebaby(self):
print("私有秘密绝招")
# hasattr
# 对象
obj = Children()
ret = hasattr(obj, 'eye')
ret = hasattr(Children, 'eye')
print(ret)
# 类
ret = hasattr(Children, 'skylight')
# ret = hasattr(Children, '__makebaby')
print(ret)
# getattr
# 对象
func = getattr(obj, "skylight")
func()
# 类
func = getattr(Children, "skylight")
func() # 报错:不是普通方法
# 第三种的不存在情况
func = getattr(obj, "asdf", "该成员不存在")
print(func)
# setattr
# 对象
setattr(obj, "eye", "white eye")
print(obj.eye)
# 类
setattr(Children, "eye", "white eye")
print(Children.eye)
setattr(Children, "tuck", lambda: print(1234))
Children.tuck()
# delattr
# 对象
delattr(obj, "eye")
print(obj.eye)
# 类
delattr(Children, "eye")
print(Children.eye)
# (2)反射模块中的成员
import sys
print(sys.modules)
# 获取本模块的对象
print(sys.modules["__main__"])
selfmodule = sys.modules["__main__"]
def func1():
print("方法一")
def func2():
print("方法二")
while True:
strvar = input("请输入你要反射的方法")
if hasattr(selfmodule, strvar):
func = getattr(selfmodule, strvar)
func()
elif strvar.upper() == "Q":
break
else:
print("没有这个方法")
二十、装饰器
装饰器:为原函数扩展新功能,用新功能去替代旧功能
作用(特点):在不改变原有代码的基础上,实现功能上的拓展
符号:@(语法糖)
核心原理:通过闭包实现
1、装饰器的八个步骤(要点):
(1)装饰器的基本用法
def kuozhan(func):
def newfunc():
print("倒水")
func()
print("放洗衣液泡,然后洗")
return newfunc
def func():
print("放衣服")
func = kuozhan(func)
func()
(2)@符号的使用
def kouzhan(func):
def newfunc():
print("起床")
func()
print("听闻哥赋诗一首")
return newfunc
@kouzhan
def func():
print("洗脸,刷牙")
func()
(3)装饰器的嵌套
注:嵌套时要注意,由近及远,由内到外执行装饰器函数
def kouzhan1(func):
def newfunc():
print("吃饭")
func()
print("上课")
return newfunc
def kouzhan2(func):
def newfunc():
print("起床")
func()
print("上厕所")
return newfunc
@kouzhan2
@kouzhan1
def func():
print("洗漱")
(4)用装饰器修饰带有参数的函数
注:扩展的新功能和原函数的功能,在参数和返回值上要保持一致
def kouzhan(func):
def newfunc(who, where):
print("起床")
func(who, where)
print("精神百倍")
return newfunc
@kouzhan
def func(who, where):
print("{who}在{where}解手".format(who=who, where=where))
func("隔壁老王", "WC")
(5)用装饰器修饰带有参数返回值的函数
注:扩展的新功能和原函数的功能,在参数和返回值上要保持一致
def kuozhan(func):
def newfunc(*args, **kwargs):
print("1")
lst = func(*args, **kwargs)
print("2")
return lst
return newfunc
@kuozhan
def func(*args, **kwargs):
dic = {"asd": "阿萨德", "zxc": "祖贤成", "qwe": "蔷薇"}
for i in args:
print("WC在", i)
return [dic[k] + "留下" + v + "黄金" for k, v in kwargs.items()]
ret = func("东边", asd="18g", zxc="18kg", qwe="18T")
print(ret)
(6)用类装饰器来拓展原函数
有两种方法:一种是通过类.函数实现;另一种是通过触发call魔术方法实现
class Kuozhan:
def __call__(self, func):
return self.kuozhan2(func)
def kuozhan1(func):
def newfunc():
print("吃饭")
func()
print("睡觉")
return newfunc
def kuozhan2(self, func):
def newfunc():
print("打游戏")
func()
print("睡觉")
return newfunc
# 方法一
@Kuozhan.kuozhan1
def func():
print("码砖进行时")
func()
# 方法二
@Kuozhan()
def func():
print("码砖进行时")
func()
(7)带有参数的函数装饰器
def outer(num):
def kuozhan(func):
def newfunc1(self):
print("洗涮1")
ret = func(self)
print("睡觉3")
return ret
def newfunc2(self):
print("洗涮4")
ret = func(self)
print("睡觉6")
return ret
if num == 1:
return newfunc1
elif num == 2:
return newfunc2
elif num == 3:
return "匆匆那年"
return kuozhan
class MyClass:
@outer(1)
def func1(self):
print("2")
@outer(2)
def func2(self):
print("5")
@outer(3)
def func3():
print("那样美丽的谣言")
obj = MyClass()
obj.func1()
obj.func2()
print(obj.func3)
(8)带有参数的类装饰器
class Kuozhan:
ad = "水中贵族百岁山"
def __init__(self, num):
self.num = num
def __call__(self,cls):
if self.num == 1:
return self.newfunc1(cls)
elif self.num == 2:
return self.newfunc2(cls)
def money(self):
print("就是小贵")
def newfunc1(self, cls):
def newfunc():
cls.ad = Kuozhan.ad
cls.money = Kuozhan.money
return cls()
return newfunc
def newfunc2(self, cls):
def newfunc():
if "run" in cls.__dict__:
ret = cls.run()
cls.run = ret
return cls()
return newfunc
obj = Kuozhan(1)
# 情况一
@Kuozhan(1)
class MyClass:
def run():
return "亢龙有悔"
obj = MyClass()
print(obj.ad)
obj.money()
# 情况二
@Kuozhan(2)
class MyClass:
def run():
return "茅中贵族,百岁山"
obj = MyClass()
print(obj.run)
2、面向对象中的方法
普通方法:可以有参数或者无参数,当成正常函数调用
普通方法(无参只能用类调用)
绑定方法:(1)绑定到对象(自动传递参数为对象)(2)绑定到类(自动传递参数为类)
绑定方法(一般用对象调用,类也能调用);
静态方法:无论是对象还是类,都可以调用,不会默认传递任何参数,如果有参数当成普通方法调用即可
class Dog:
name = "旺财"
# 普通方法
def jiao():
print("小狗汪汪叫")
# 绑定方法(对象)
def eat(self):
print("小狗喜欢吃骨头")
# 绑定方法(类)
@classmethod
def tail(cls):
print(cls)
print("小狗看到主人喜欢摇尾巴")
# 静态方法
@staticmethod
def jump(num):
print("小狗喜欢接飞盘")
obj = Dog()
# 普通方法
Dog.jiao()
# 绑定方法(对象)
obj.eat()
Dog.eat(1234)
# 绑定方法(类)
Dog.tail()
obj.tail()
# 静态方法
obj.jump(1)
Dog.jump(2)
# 在类外,为对象添加成员方法,默认都是静态方法
obj.func = lambda: print(1234)
obj.func()
3、property装饰器
property 可以把方法变成属性使用
作用:控制属性的获取,设置,删除等操作
变相的增加成员的安全性,可以通过自定义逻辑对成员进行控制
自动触发:要求:是同一个名字
注:可以通过pass对property进行权限限制,使用pass代表不会执行该操作
# 使用方法一
class MyClass:
def __init__(self, name):
self.name = name
@property
def username(self):
# pass
return self.name
@username.setter
def username(self, val):
# pass
print(112233)
val = "阿萨德"
self.name = val
@username.deleter
def username(self):
# pass
del self.name
# 获取属性 (自动触发获取方法 @property)
obj = MyClass("许多")
print(obj.username)
# 设置属性 (自动触发设置方法) val形参自动接收设置的值
obj.username = "阿萨"
print(obj.username)
# 删除属性
del obj.username
print(obj.username) # error
# 使用方法二
class MyClass:
def __init__(self, name):
self.name = name
# 获取
def get_username(self):
return self.name
# 设置
def set_username(self, val):
self.name = val
# 删除
def del_username(self):
del self.name
useranme = property(get_username, set_username, del_username)
# 获取
obj = MyClass("朴飘乐")
print(obj.useranme)
# 设置
obj.useranme = "朴一生"
print(obj.useranme)
# 删除
del obj.useranme
print(obj.useranme)