zoukankan      html  css  js  c++  java
  • 封装-property装饰器-反射

    一、super进阶

    在多继承中:严格按照mro顺序来执行

    super是按照mro顺序来寻找当前类的下一类

    在py3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法

    在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象). 函数名()

    这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法

    在py2的经典类中,并不支持使用super来找下一个类

    class A:
        def func(self):         
            print('is A')       
    ​
    ​
    class B(A):
        def func(self):
            super().func()      
            print('is B')
    ​
    ​
    class C(A):
        def func(self):
            super().func()      
            print('is C')
    ​
    ​
    class D(B, C):
        def func(self):
            super().func()      
            print('is D')
    ​
    d = D()
    print(D.mro())
    d.func()
    ​
    # 输出
    [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    is A
    is C
    is B
    is D

    在单继承中:super就是找父类

    class Foo:
        def func(self):
            print('is Foo')
    ​
    class Son(Foo):
        def func(self):
            super().func()     # 先找父类的func方法--->打印is Foo
            print('is Son')             # 在打印自己的is Son
    ​
    ​
    s = Son()
    s.func()
    # 输出
    is Foo
    is Son

    二、封装

    封装:就是把属性或方法装起来

    广义:把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用

    狭义:把属性和方法藏起来,外面不能调用,只能在内部偷偷调用

    所有的私有化都是为了让用户不在外部调用类中的某个名字

    如果完成私有化,那么这个类的封装度就更高了,封装度越高各种属性和方法的安全性也越高,但代码越复杂

    封装的语法:

    1、给一个名字前面加上了双下滑线的时候,这个名字就变成了一个私有的

    2、所有私有的内容或者名字都不能在类的外部调用,只能在类的内部使用了

    # 不想让你看也不想让你改
    class User:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd        # 私有的实例变量/私有的对象属性
    ​
    use = User('admin', 'abc123')
    ​
    print(use.__pwd)        # 报错
    print(use.pwd)          # 报错

    在外部查看和修改私有对象属性:

    # 可以给你看也可以给你改,但你要用我自定义的方法看,和按照我的规则改
    class User:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    ​
        def get_pwd(self):              # 表示用户不能改只能看
            return self.__pwd
        
        def change_pwd(self, count):    # 表示用户必须调用我们自定义的修改方式来进行变量的修改
            if count.isdigit():         # 是数字我就改,不是我就不改,还是原样
                self.__pwd = count
            return self.__pwd
    ​
    use = User('admin', 'abc123')
    ​
    print(use.get_pwd())
    use.change_pwd('123456789')     # 实际上是调用了对象内部的函数进行修改
    print(use.get_pwd())
    # 输出
    abc123
    123456789
     

    1、加了双下划线的名字为啥不能从外部调用了?

    class User:
        __Country = '中国'         # 私有的静态变量
        __job = '攻城狮'           # 私有的静态变量
    def func(self):
            # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形(_User__Country)
            print(User.__Country)   # __Country已经变形成(_User__Country)
    print(User.__dict__)
    User().func()
    ​
    '''
    此时,变量做了一个转换所以在外部找不到了,如果外部调用转换后的变量还是可以调用的。(但不介意这样用)
    __Country ---> _User__Country
    __job     ---> _User__job
    '''
    # 输出
    {..., '_User__Country': '中国', '_User__job': '攻城狮',...}
    中国

    2、私有的内容不能被子类使用。

    class Foo:
        # __func:为私有的绑定方法
        def __func(self):       # 3、而父类Foo中的私有方法已经变形为_Foo__func了不是_Son__func方法了
            print('is Foo')
    ​
    class Son(Foo):
        def __init__(self):
            self.__func()       # 2、子类__func方法变形成了_Son__func方法了,没有会去父类Foo找
    ​
    Son()       # 1、实例化时,自动调用init方法
    # 输出 报错
    AttributeError: 'Son' object has no attribute '_Son__func'

    3、在其他语言中的数据的级别都有哪些?在python中有哪些?

    public 公有的 类内类外都能用,父类子类都能用 python支持

    protect 保护的 类内能用,父类子类都能用,类外不能用 python不支持

    private 私有的 本类的类内部能用,其他地方都不能用 python支持

    三、内置的装饰器:property,setter,delter

    property方法:把一个方法伪装成属性,在掉用这个方法的时候不需要加()就可以直接得到返回值。

    方法一:

    from math import pi
    ​
    class Circle:
        def __init__(self, r):
            self.r = r
    ​
        @property       # 把area()函数伪装成属性
        def area(self):
            print(pi * self.r ** 2)
    ​
    ​
    # 实例化一个半径为5的圆
    y = Circle(5)
    y.area      # 被伪装后圆的面积函数不用加()
    # 输出
    78.53981633974483

    方法二:和私有的属性合作的

    class User:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    ​
        @property
        def pwd(self):
            print(self.__pwd)
    ​
    ​
    u = User('小杨', '1234')
    u.pwd
    # 输出
    1234

    setter方法:对伪装方法可以使用和属性一样的 = 号了

    class User:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    ​
        @property
        def pwd(self):
            print(self.__pwd)
    ​
        @pwd.setter
        def pwd(self, count):
            print('我这里setter被调用了')
            if isinstance(count, int):  # 满足条件(count是int类型)我就修改
                self.__pwd = count
    ​
    ​
    ​
    u = User('小杨', '1234')
    u.pwd = 1111    # 可以使用 = 进行满足条件的赋值了,不满足原样不变
    u.pwd
    ​
    # 输出
    我这里setter被调用了
    1111

    delter方法:(了解)

    class User:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    
        @property
        def pwd(self):
            print(self.__pwd)
    
        @pwd.deleter
        def pwd(self):
            print('我这里delter被调用了')
    
    
    u = User('小杨', '1234')
    
    del u.pwd
    # 输出
    我这里delter被调用了

    四、反射getatter、hasatter

    反射:用字符串类型的名字来操作这个名字对应的函数、实例变量、绑定方法、各种方法

    在明明知道一个变量的字符串数据类型的名字,想直接调用它,但是调不到的时候,用反射

    getattr方法:

    1、反射对象的:实例变量、绑定方法

    class Person:
        def __init__(self, name , age):
            self.name = name
            self.age = age
    ​
        def func(self):
            print('is func')
    ​
    # 实例化一个对象
    Bob = Person('鲍勃', 18)
    ​
    print(getattr(Bob, 'name'))     # 反射对象的实例变量
    getattr(Bob, 'func')()          # 反射对象的绑定方法
    # 输出
    鲍勃
    is func

    2、反射类的:静态变量

    class Person:
        attribute = '会思考'def __init__(self, name, age):
            self.name = name
            self.age = age
    ​
        def func(self):
            print('is func')
    ​
    ​
    print(getattr(Person, 'attribute'))     # 反射类的静态变量
    # 输出
    会思考

    3、反射模块中的所有变量

    反射被导入的模块:

    # 模块 my_module.py 内容
    count = '模块 my_module.py 中count的内容'def func():
        return '这是 my_module 模块中的 func 函数'# --------------------------------------------------------------
    import my_module
    ​
    ret = getattr(my_module, 'count')
    ret2 = getattr(my_module, 'func')
    print(ret)
    print(ret2())
    # 输出
    模块 my_module.py 中count的内容
    这是 my_module 模块中的 func 函数

    4、反射当前执行的py文件 ——> 当前脚本

    import sys
    ​
    lis = [1, 2, 3]
    ​
    def func():
        return 'is func'
    ​
    ret1 = getattr(sys.modules['__main__'], 'lis')      # 反射当前脚本的变量
    ret2 = getattr(sys.modules['__main__'], 'func')     # 反射当前脚本的函数
    print(ret1)
    print(ret2())
    # 输出
    [1, 2, 3]
    is func

    hasattr方法:

    hasattr 方法其实是和 getattr 方法成对使用的,主要用来判断反射变量是否存在

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def func(self):
            print('is func')
    
    
    Bob = Person('鲍勃', 18)
    print(hasattr(Bob, 'name'))     # name 变量名存在就返回True
    print(hasattr(Bob, 'sex'))      # sex 变量不存在就返回False
    
    if hasattr(Bob, 'func'):                    # 判断 func 是否存在
        # 存在,判断 func 是否可以被调佣(用 callable 判断是否是函数)
        if callable(getattr(Bob, 'func')):      
            getattr(Bob, 'func')()              # 是函数就加括号()
        getattr(Bob, 'func')                    # 不是就不用加括号()
    
    # 输出
    True
    False
    is func

    五、反射例子

    反射例子一:

    import sys
    ​
    class WeChat:
        def __init__(self, username):
            self.username = username
    ​
        def pay(self, money):
            print(f'{self.username}通过微信充值了{money}')
    ​
    class Alipay:
        def __init__(self, username):
            self.username = username
    ​
        def pay(self, money):
            print(f'{self.username}通过支付宝充值了{money}')
    ​
    ​
    # 简化归一化设计:
    def pay(username, money, kind):
        class_name = getattr(sys.modules['__main__'], kind)     # 输入的类名,反射本地的类
        obj = class_name(username)             # 用上一步反射的类来创建实例化对象
        obj.pay(money)
    ​
    pay('小杨', 200, 'WeChat')
    ​
    # 输出
    小杨通过微信充值了200

    反射例子二:

    用户输入用户名密码性别

    实例化对象

    用户任意输入内容 : 不能用异常处理

    如果输入的是属性名 打印属性值

    如果输入的是方法名 调用方法

    如果输入的什么都不是 不做操作

    class User:
        def __init__(self, name, pwd, sex):
            self.name = name
            self.pwd = pwd
            self.sex = sex
    ​
        def eat(self):
            print(f'{self.name},在吃饭')
    ​
        def sleep(self):
            print(f'{self.name},在睡觉')
    ​
    ​
    Bob = User('鲍勃', 18, '')
    ​
    count = input('需要操作的方法:')
    ​
    if hasattr(Bob, count):
        if callable(getattr(Bob, count)):
            getattr(Bob, count)()
        print(getattr(Bob, count))

    反射例子三:

    循环这个列表 显示 序号 用户要做的操作

    用户输入序号

    你通过序号找到对应的login或者register方法

    先实例化

    调用对应的方法,完成登录或者注册功能

    class Authentic:
        ll = [('登录', 'login'), ('注册', 'register')]
    ​
        def __init__(self, username, pwd):
            self.username = username
            self.pwd = pwd
    ​
        def register(self):
            print('注册成功:')
    ​
        def login(self):
            print('登录成功:')
    ​
    ​
    Bob = Authentic('python', 123456)
    ​
    for index, func in enumerate(Authentic.ll, 1):  
        print(index, func[0])
    ​
    count = int(input('请选择需要操作的序号>>:'))
    if hasattr(Bob, Authentic.ll[count - 1][1]):
        getattr(Bob, Authentic.ll[count - 1][1])()
    # 输出
    1 登录
    2 注册
    请选择需要操作的序号>>:2
    注册成功:
    学习之旅
  • 相关阅读:
    Linux各主要发行版的包管理命令对照
    JDK 生成数字证书
    AbatorForEclipse插件使用总结
    [转载]在rhel 6 x86_64 上安装oracle 11g xe
    【转载】PL/SQL配置连接ORACLE
    Archlive新年第一棒: 基于2.6.37稳定内核的archlive20110107
    基于Arch的live系统
    【转】MyEclipse 9.0正式版官网下载(附Win+Llinux激活方法、汉化包)
    Exception in thread main java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFacto
    MyEclipse 8.6插件下载
  • 原文地址:https://www.cnblogs.com/XiaoYang-sir/p/14730323.html
Copyright © 2011-2022 走看看