反射和装饰器

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值