zoukankan      html  css  js  c++  java
  • 魔力Python——对象

      Python之中,一切皆对象.

       本文分为4部分:

      1. 面向对象:初识

      2. 面向对象:进阶

      3. 面向对象:三大特性----继承,多态,封装

      4. 面向对象:反射

    0. 楔子

    面向过程和面向对象的是两种思路:

    面向过程是流水线,闷着头一口气写下来就行;

    面向对象,感觉自己像是个上帝,先构思好,然后再去写,这也是我们写程序时候要做到的.

    例子如下:

    #面向过程,函数:
    def login():
        pass
    def regisgter():
        pass
    
    def func1():
        pass
    def func2():
        pass
    
    #面向对象,类:
    class Account:
        def login(self):
            pass
        def regisgter(self):
            pass
    
    class Account:
        def func1(self):
            pass
        def func2(self):
            pass

      从上面的式子,我们很容易发现:

        1.类相当于函数的集合,能够让你的函数更加集中,不是那么散乱.

        2.用类的话有上帝视角. 倒也算不上哪个好哪个坏,无非是复杂的话用类好,简单的话用函数好.

    1. 面向对象:初识

      1.1 什么是对象和类

      什么是对象?  人说,Python中,一切皆对象. 这么说似乎有些宽泛, 一切, 究竟包括什么呢?

      其实,这里的一切是指所有的变量. 在之前我们已经学习了字符串等数据类型,也学习了函数和内置函数,还学会了内置模块和第三方模块的调用. 那么,这些都是对象吗?是的,一切皆对象. 只要我们能够将其赋给变量,甚至连模块都可以赋给变量,那么还有什么不是变量呢?

      最近学到的一个经典例子:人狗大战. 这个例子可以生动形象的解释.

      如果我们需要进行人和狗进行战斗这样一个场景,我们需要的内容是:

      人的要素,比如生命值,攻击力,防御力,职业;狗的要素,生命值,攻击力,防御力,种类.

      创建完两个角色的属性后,我们需要让他们发生互动,也就是'fight'.

      但如果这时候,我们想要创建好几个人和狗怎么办呢? 很简单,我们只要把人和狗做成模子即可,就像活字印刷术,排完版之后蘸上墨水刷一下就好啦. 光想着这么多的东西,如果要是用函数的话,很容易没有条理的,尤其是创建人物和动物形象的时候.

      用函数做法如下:

    def Person(name,hp,ad,sex):   # 模子
        dic = {'name':name,'blood':hp,'attack':ad,'sex':sex}
    
        def fight(dog):  # 攻击  属于人
            # 狗掉血,就是人的攻击力
            dog['blood'] -= dic['attack']
            print('%s打了%s,%s掉了%s血' % (dic['name'], dog['name'], dog['name'], dic['attack']))
        dic['fight'] = fight
        return dic
    
    def Dog(name,hp,ad,kind):
        dic = {'name': name, 'blood': hp, 'attack': ad, 'kind': kind}
    
        def bite(person):  # 咬 属于狗
            person['blood'] -= dic['attack']
            print('%s咬了%s,%s掉了%s血' % (dic['name'], person['name'], person['name'], dic['attack']))
    
        dic['bite'] = bite
        return dic
    # 互相打
    smith = Person('smith',20,1,'不详')
    print(smith)
    hei = Dog('小黑',3000,10,'哈士奇')
    print(hei)
    smith['fight'](hei)
    hei['bite'](smith)

      说实话,是不是感觉乱乱的?  

      这时候,救星来了! 我们用类可以轻松做到!!!

    class Dog:
        def __init__(self,name,blood,ad,kind):
            self.name = name  # 向对象的内存空间中添加属性
            self.hp = blood   # 可以通过self在类的内部完成
            self.ad = ad
            self.kind = kind
    
        def bite(self,person):
            person.hp -= self.ad
            print('%s攻击了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad))
    
    class Person:
        def __init__(self,name,hp,ad,sex):
            self.name = name
            self.hp = hp
            self.ad = ad
            self.sex = sex
    
        def fight(self,dog):
            dog.hp -= self.ad
            print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad))

      这样,两个模子已经刻好了,并且将动作也定义完了(此处就是方法),当我们想创建的时候,就可以轻松创建,如下:

    hei = Dog('小黑',300,20,'哈士奇')
    alex = Person('alex',20,1,'不详')
    alex.fight(hei)
    print(hei.hp)
    hei.bite(alex)
    print(alex.hp)

      这样,上面的就是创建类,下面的就是实例化对象并且进行方法的调用.(其中__init__是属性)

      类:具有相同方法和属性的一类事物

      对象:具有相同的属性值的实际存在的例子. 此处,对象仅指实例化的对象.是狭义的. 

        广义的对象包括类.

      1.2 类的结构和类的操作

      类的结构基本如下:

    class 类名:#切记,类名首字母大写,为了和系统内置的类区分开
        def __init__():#可有可无,不是必须写的
            pass
        def  方法名():
            pass

      查看类中变量的两种方法如下:

    def 函数:
        pass
    class Dog:
        pass
    class Dog:
        变量 = 1000
        变量2 = 'abc'
    #  变量3 = [(1,2),(3,4)]
    
    查看类当中的变量,方法一
    print(Dog.__dict__['变量'])
    print(Dog.__dict__['变量2'])
    print(Dog.__dict__['变量3'])
    查看方法二(常用)
    print(Dog.变量)
    print(Dog.变量2)
    print(Dog.变量3)

      其中,若用Dog.__dict__可查看Dog的全部属性,当然也可以用此方法查看实例化的对象等.

      调用类中静态变量的方法一致.

    #续上列:
    class Cat:
        cat_of_producing = '猫舍'#理解为刷怪区吧,是静态变量
        def __init__(self,name,hp):
            self.name = name
            self.hp = hp
        def catch(self):
            print('捕捉成功')        
    print(Cat.cat_of_producing)#此时就能调用静态变量
    #类名可以调用动态方法,但一般不用.
    #实例化对象也可以调用静态变量,能查能改.
    #但改的话一般用类名调用.

      非常需要注意:::::::::::::::::::::::::::::::::::::

     

      注意,当编译完了的时候,class就出现了其内存空间.当进行实例化的时候,其实例化对象也产生了一个内存空间.切记.

      

    实例化的过程 :
    1.开辟了一块空间,创造了一个self变量来指向这块空间
    2.调用init,自动传self参数,其他的参数都是按照顺序传进来的
    3.执行init
    4.将self自动返回给调用者

        PS:

      1.类名可以调用所有定义在类中的名字
      变量
      函数名
      2.对象名 可以调用所有定义在对象中的属性
      在init函数中和self相关的
      调用函数的,且调用函数的时候,会把当前的对象当做第一个参数传递给self

    2. 面向对象:进阶

      2.0 回顾

        回顾上述内容,记得设置完属性和动作之后让他们进行互动.

    class Monster:
        # 先生成一个怪物的形象
        def __init__(self, name, hp, attack, type):
            self.name = name
            self.hp = hp
            self.attack = attack
            self.type = type
    
        # 然后再生成一个怪物的动作
        def fight(self, person):
            person.hp -= self.attack
            print('%s对%s造成%s点伤害,%s还剩%s点血' % (self.name, person.name, self.attack, person.name, person.hp))
    
    
    class Hero:
        # 同理,先生成一个英雄的形象
        def __init__(self, name, hp, attack, sex):
            self.name = name
            self.hp = hp
            self.attack = attack
            self.type = type
    
        # 然后再生成一个怪物的动作
        def fight(self, monster):
            monster.hp -= self.attack
            print('%s对%s造成%s点伤害,%s还剩%s点血' % (self.name, monster.name, self.attack, monster.name, monster.hp))
    
    
    # 对人物和怪兽进行实例化
    arthur = Hero('King_Arthur', 50, 20, 'male')
    siren1 = Monster('海妖1号', 200, 10, 'siren')
    #经过千辛万苦,我们的亚瑟王最终和海妖战斗在一起,并且各砍一刀
    arthur.fight(siren1)#King_Arthur对海妖1号造成20点伤害,海妖1号还剩180点血
    siren1.fight(arthur)#海妖1号对King_Arthur造成10点伤害,King_Arthur还剩40点血
    #天呐,看来我们的亚瑟王如果不逃走的话将会命丧海妖之手,但是,,,,,,这跟我有什么关系呢哈哈哈哈哈
    
    #为了增加游戏的趣味性,我们可以再加上武器系统,比如再建一个class Weapon,然后通过动作进行武器装备,还可以加上防御力和
    # 闪避等属性,可操作性太多了.

        为了纪念这场差点把亚瑟王杀死的旷世大战,我准备把这个小游戏命名为世纪之战.

        记得,只要上面的世纪之战吃透,简单的写一个小小的自娱自乐的游戏至少是没问题哒.

      2.1 内存空间

      2.2 私有化(正常来说应当放到封装,但因为一些特殊原因放于此)

      2.3 类的特殊成员(前面有两道下划线的内置方法)

      

      2.1 内存空间

        内存空间:一般是指主存储器空间(物理地址空间)或系统为一个用户程序分配内存空间。

        内存地址:内存地址是内存当中存储数据的一个标识,并不是数据本身,通过内存地址可以找到内存当中存储的数据。由4位或8位16进制表示.

      2.2 私有化

        在前面加__即可,表明只有这个方法是由某类私有的.别的是调用不了的.

      2.3 类的特殊成员

        用到的时候可参考:https://www.jianshu.com/p/bf3166d8faf0

                 https://www.cnblogs.com/pyxiaomangshe/p/7927540.html

        之前的方法已经能够解决日常的90%了,我们需要解决的10%可以从内置方法中找到答案.

        内置方法又被称为双下方法,魔术方法.都是python的对象内部自带的,并且都不需要我们自己去调用它.

        2.3.1 __str__和__repr__

    class Course:
        def __init__(self,name,price,period):
            self.name = name
            self.price = price
            self.period = period
        # def __str__(self):#
        #     """
        #     打印这个对象的时候自动触发__str__
        #     :return:
        #     """
        #     return '%s,%s,%s'%(self.name,self.price,self.period)
        # def __repr__(self):#备胎(str没有的时候才用repr)
        #     """
        #     打印这个对象的时候自动触发__str__
        #     :return:
        #     """
        #     return '%s,%s,%s'%(self.name,self.price,self.period)
    
    python = Course('python',25000,'6 mouths')
    print(type(python))
    # print('course:%s'%python)
    # print(f'course:{python}')

        如果str存在,repr也存在,那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__,而repr(obj)和%r格式化字符串,都会调用__repr__ ;
        如果str不存在,repr存在,那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__.
        如果str存在,repr不存在,那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__.
        repr(obj)和%r格式化字符串,都会打印出内存地址.

    class Course:
        def __init__(self,name,price,period):
            self.name = name
            self.price = price
            self.period = period
        def __repr__(self):#备胎(str没有的时候才用repr)
            """
            打印这个对象的时候自动触发__str__
            :return:
            """
            return '%s,%s,%s'%(self.name,self.price,self.period)
        # def __str__(self):
        #     return self.name
    
    class Python(Course):
        pass
        def __repr__(self):
            return '%s--%s--%s' % (self.name, self.price, self.period)
        # def __str__(self):
        #     return '全栈开发:'+self.name
    
    python = Python('python',25000,'6mouths')
    print(python)
    #放开Courese和Python的str,显示为:全栈开发:python
    #放开Courese的str和Python的repr,显示为:python
    #放开Courese的repr和Python的str,显示为:全栈开发:python
    #放开Courese和Python的repr,显示为:python--25000--6mouths
        有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了.
        增强了用户的体验 在程序开发的过程中,如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,
      实际上是一种麻烦.

        如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示.

        2.3.2 __new__和__del__

        __new__ 构造方法 生产对象的时候用的 - 单例模式
        __del__ 析构方法 在删除一个对象之前用的 - 归还操作系统资源

        实例化一个Foo的对象,先开辟一块儿空间,使用的是Foo这个类内部的__new__.
        如果我们的Foo类中是没有__new__方法的,调用object类的__new__方法了

        在使用self之前,都还有一个生产self的过程,就是在内存中开辟一块属于这个对象的空间,并且在这个空间中存放一个类指针,以上就是__new__做的所有事情.

    #__new__的实例:
    class Foo(object):
        def __new__(cls, *args, **kwargs): # cls永远不能使self参数,因为self在之后才被创建
            obj = object.__new__(cls)   # self是在这里被创造出来的
            print('new : ',obj)
            return obj
        def __init__(self):
            print('init',self)
    Foo()
    #关于__del__的一些解释
    #在所有的代码都执行完毕之后,所有的值都会被python解释器回收

      #python解释器清理内存

      #1.我们主动删除 del obj
      #2.python解释器周期性删除
      #3.在程序结束之前 所有的内容都需要清空

     

    #
    __del__的实例1: import time class A: def __init__(self,name,age): self.name = name self.age = age def __del__(self): #只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容 print('执行我了') a = A('gh',84) # print(a.name) # print(a.age) # del a print(a)#执行完后自动清理
    #__del__的实例2:
    import time
    class A:
        def __init__(self,path):
            self.f = open(path,'w')
        def __del__(self):
            '''归还一些操作系统的资源的时候使用'''
            '''包括文件网络数据库连接'''
            self.f.close()
    
    a = A('userinfo')
    time.sleep(1)

        PS:拓展:单例模式

          设计模式 - 单例模式
          一个类 有且只能有一个实例

          保证一个类无论 被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址

    class A:pass
    a1 = A()
    a2 = A()
    print(a1)
    print(a2)
    
    class A:
        __flag = None
        def __new__(cls, *args, **kwargs):
            if cls.__flag is None:
                cls.__flag = object.__new__(cls)
            return cls.__flag
    
        def __init__(self,name=None,age=None):
            self.name = name
            if age:
                self.age = age
    
    a1 = A('alex',84)
    print(a1)
    a2 = A('alex',83)
    print(a2)
    a3 = A('alex')
    print(a3)
    print(a1.age)#结果为83,说明最后一次覆盖掉了

        2.3.3 __call__

    #__call__
    #源码里用比较多 Flask web框架
    #对象()自动触发__call__中的内容
    class A:
        def call(self):
            print('in call')
        def __call__(self, *args, **kwargs):#自动调用__call__
            print('in __call__')
    
    # A()()
    obj = A()
    obj()
    obj.call()
    转载自:https://segmentfault.com/q/1010000006113393?_ea=1020343(好吧,表示现在看的还不是太懂)
    用一句话描述是, Python 的
    __call__ 方法可以让类的实例具有类似于函数的行为,通常用于定义和初始化一些带有上下文的函数。 既然说是妙处,那不得不提及 Python 世界中的那几个经典实现了。 一个例子来源于 bottle 框架源码的 cached_property(被我改动了一些细节,但用法基本是一样的),为了在逻辑上构成一个封闭的整体,我们把一个实例当作函数来使用: class CachedProperty(object): _cache = {} def __call__(self, fn): @property @functools.wraps(fn) def wrapped(self): k = '%s:%s' % (id(self), fn.__name__) v = CachedProperty._cache.get(k) if v is None: v = fn(self) CachedProperty._cache[k] = v return v return wrapped cached_property = CachedProperty() 使用的时候可以直接替换掉内置的 property 来缓存动态属性: class DB(object): def __init__(self, ...): .... @cached_property def conn(self): return create_connection(...) db = DB() db.conn # 创建连接并缓存 还有个更复杂但非常实用的例子,Pipline,把函数封装成支持管道操作的运算过程: class Pipe(object): def __init__(self, fn): self.fn = fn def __ror__(self, other): return self.fn(other) def __call__(self, *args, **kwargs): op = Pipe(lambda x: self.fn(x, *args, **kwargs)) return op 可以像这样调用: @Pipe def sort(data, cmp=None, key=None, reverse=False): return sorted(data, cmp=cmp, key=None, reverse=reverse) [{'score': 1}, {'score': 3}, {'score': 2}] | sort(key=lambda x: x['score']) 可以看出,类 Pipe 被当作一个装饰器使用,所以 sort 函数的原始定义被传递给 Pipe.__init__,构造出一个 Pipe 实例,所以被装饰过的 sort 函数,也就是我们后面使用的那个,实际上是一个 Pipe 类的实例,只是因为它有 __call__ 方法,所以可以作为函数来使用。 这种用法在写一些 ORM 框架以及有大量细粒度行为的库时有奇效。

        2.3.4 __enter__,__exit__与with的完美结合

        自动识别__enter__和__exit__
        判定__enter__执行为开始,__exit__为结束
        应用场景应当有很多:比如

    执行语句体:
    class File:
        def __enter__(self):
            print('start')
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit')
    
    with File():
        print('wahaha')#相当于装饰器,输出顺序是
                                #start
                                #wahaha
                                #exit
    写入文件:
    class myopen:
        def __init__(self,path,mode = 'r'):
            self.path = path
            self.mode = mode
        def __enter__(self):
            print('start')
            self.f = open(self.path,mode=self.mode)
            return self.f
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.f.close()
            print('exit')
    
    with myopen('userinfo','a')as f:
        f.write('hello,world')
    用pickle模块写入文件:
    import pickle
    class MypickleDump:
        def __init__(self,path,mode='ab'):
            self.path = path
            self.mode = mode
        def __enter__(self):
            self.f = open(self.path,self.mode)
            return self
        def dump(self,obj):
            pickle.dump(obj,self.f)
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.f.close()
    
    with MypickleDump('pickle_file')as pickle_obj:
        pickle_obj.dump({1,2,3})

        第三种写入文件,请比较异同:

    class MypickleDump:
        def __init__(self,path,mode = 'ab'):
            self.path = path
            self.mode = mode
    
        def __enter__(self):
            self.f = open(self.path,self.mode)
            return self
    
        def dump(self,obj):
            pickle.dump(obj,self.f)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.f.close()
    
    with MypickleDump('pickle_file') as obj:
        obj.dump({1,2,3,4})
    
    with MypickelLoad('pickle_file') as obj:
       for i in  obj.loaditer():
           print(i)

        在一个函数的前后添加功能
        利用使用 装饰器函数中的内容

        with语句 就是和 __enter__,__exit__完美结合,请注意使用哦.

         

        ############################

          划    重    点

        ############################

        基础:
         __new__
         __del__
         __call__
        重点:
         __str__
         __repr__
         __enter__
         __exit__

    3. 面向对象:继承,多态,封装

      初入对象,感觉的确挺有意思,凡事都是那么简单的感觉,上帝视角,随意调用人物属性,随意设置任务动作,那滋味简直不要太爽!!!

      然而,记得一个公式:痛苦==有益,爽==有害.一旦只沉迷于这种感觉,很容易不思进取,因为再往下就会感觉有些难度了.

    图中虚线代表实例关系,实线表示继承关系,从这个图中得出几点:

    1. list、str、dict、tuple、type都继承了object,所以object是最顶层的基类

    2. type是本身的对象(实例),object、list、str、dict、tuple都是type的对象,所以type创建了所有的对象

    3. 综合1、2可知,一切皆对象的同时又继承了object类,这就是python的灵活之处,Python的面向对象更加彻底.

      其实,object也是继承元类(metaclass)得来的.

    PS:(转载自王sir)
    关于抽象类的理解:
    1.抽象类的意义是?或者说为什么要有抽象类? 抽象类是对多个类中共同方法的抽取,但是子类又有不同的实现,父类只能抽取出方法的名字,而不明确方法的具体实现. 这种只规定子类拥有哪些方法,而不明确具体实现的父类,就应该定义为抽象类. 抽象类只用来规范子类应该具有哪些行为,而不明确具体的动作. 2.抽象类的特点是? 抽象类和普通类的最主要区别在于: 1.抽象类继承的()中写的是metaclass=ABCMeta 2.在类体中有用@abstractmethod修饰的方法(需要子类重写的方法) 3.抽象类中是否可以有非抽象方法? 可以. 4.抽象类中的抽象方法是否可以有方法体? 可以. 5.抽象类中是否可以有__init__方法?为什么? 可以,因为抽象类中也可以有实例属性供子类继承. 而实例属性必须在父类中初始化,子类对象才能继承. 抽象类的__init__方法不能手动调用,只能是子类创建对象时自动调用的.

    4. 面向对象:反射

      首先,要明确一点的是,反射的格式:a.b <====> getattr(a,'b') 诸如此类,这是核心概念!!!!!

        所有的a,b都可以变成getattr(a,'b')
        用字符串数据类型的变量名 来获取实际的变量值
        用字符串数据类型的变量名 找到这个变量对应的内存地址

      4.1 两个内置函数

        issubclass

    # class A:pass
    # class B(A):pass
    # class C(A):pass
    # print(issubclass(B,A))
    # print(issubclass(C,A))
    # print(issubclass(B,C))#只针对类
    # print(isinstance(B,A))#只针对对象与类

        isinstance

    # a = 1
    # ret1 = type(a) is int
    # print(ret1)
    # ret2 = isinstance(a,int)
    # ret3 = isinstance(a,object)
    # print(ret2)
    # print(ret3)

        小结:

        两个内置函数
          isinstance()判断对象与类是否有继承关系
          type()判断对象与类是否有关系(只承认实例化对象的那个类,不承认继承关系)
          issubclass()判断类与类是否有继承关系

      4.2 一个套餐,4个函数

        内置函数:
        getattr
        hasattr
        setattr
        delattr

        4.2.1 hasattr()

          用途:hasattr#判断是否找到对象,判断True 或者 False

            格式:hasattr(a,'b'),返回True或者False. 常与getattr()连用,判断是否可以调用,避免报错.

        4.2.2 getattr()

          用途:getattr#找到对象对应的内存地址,调用字符串作为属性名

          格式:getattr(a,'b'),等同于a.b 

    if hasattr(s,'choose_goods'):   # 判断s对象有没有choose_goods
        func = getattr(s,'choose_goods')   # 使用s找到choose_goods对应的内存地址
        print(func)
        func()

            PS:若想调用变量a或b,但只能输入'a'或'b'.

    a = 1
    b = 2
    getattr(modules[__name__],'变量名')#这个一定要牢记!!!

        4.2.3 setattr()

          用途:用于添加,有三个变量.

          格式:setattr(x, 'y', v) is equivalent to ``x.y = v''#官方解释

    setattr(alex,'wahaha',wahaha)
    print(alex.__dict__)
    alex.wahaha(alex)

         4.2.4 delattr()

          用途:用于删除

          格式:delattr(x, 'y') is equivalent to ``del x.y''#官方解释

    delattr()
    print(smith.__dict__)
    delattr(smith,'name')   # del smith.name
    print(smith.__dict__)

      4.3 四种反射情况

        4.3.1 使用对象反射

          obj.属性名

          obj.方法名()

    # 1.使用对象反射(先列出类)
    # class Manager:   # 管理员用户
    #     def __init__(self,name):
    #         self.name  = name
    #     def create_course(self):  # 创建课程
    #         print('in Manager create_course')
    #
    #     def create_student(self): # 给学生创建账号
    #         print('in Manager create_student')
    #
    #     def show_courses(self): # 查看所有课程
    #         print('in Manager show_courses')
    #
    #     def show_students(self): # 查看所有学生
    #         print('in Manager show_students')
    # 不用反射
    # alex = Manager('alex')
    # operate_lst = ['创建课程','创建学生账号','查看所有课程','查看所有学生']
    # for index,opt in enumerate(operate_lst,1):
    #     print(index,opt)
    # num = input('请输入您要做的操作 :')
    # if num.isdigit():
    #     num = int(num)
    # if num == 1:
    #     alex.create_course()
    # elif num == 2:
    #     alex.create_student()
    # elif num == 3:
    #     alex.show_courses()
    # elif num == 4:
    #     alex.show_students()
    # 使用反射
    # alex = Manager('alex')
    # operate_lst = [('创建课程','create_course'),('创建学生账号','create_student'),
    #                ('查看所有课程','show_courses'),('查看所有学生','show_students')]
    # for index,opt in enumerate(operate_lst,1):
    #     print(index,opt[0])
    # num = input('请输入您要做的操作 :')
    # if num.isdigit():
    #     num = int(num)
    #     if hasattr(alex,operate_lst[num-1][1]):
    #         getattr(alex,operate_lst[num-1][1])()

        4.3.2 使用模块反射   

    import time
    time.time()
    
    调用函数和方法 地址+()
    def func():
        print(1)
    
    func()
    a = func
    a()
    # 反射模块中的方法
    import re
    # ret = re.findall('d+','2985urowhn0857023u9t4')
    # print(ret)
    # 'findall'
    # getattr(re,'findall')   # re.findall
    # ret = getattr(re,'findall')('d','wuhfa0y80aujeiagu')
    # print(ret)
    
    # def func(a,b):
    #     return a+b
    
    # wahaha = func
    # ret = wahaha(1,2)
    # print(ret)

        4.3.3 使用类反射

          cls.静态变量名
          cls.类方法名()
          cls.静态方法名()

    # 两种方式
        # 对象名.属性名 / 对象名.方法名() 可以直接使用对象的方法和属性
        # 当我们只有字符串数据类型的内容的时候
            # getattr(对象名,'方法名')()
            # getattr(对象名,'属性名')

        4.3.4 反射当前文件

    # 反射本文件中的内容 :只要是出现在全局变量中的名字都可以通过getattr(modules[__name__],字符串数据类型的名字)
    from sys import modules
    # print(modules)    # DICT KEY是模块的名字,value就是这个模块对应的文件地址
    
    # import re
    # print(re)   # <module 're' from 'D:\python3\lib\re.py'>
    # print(modules['re'])
    # 选课系统
    # 're': <module 're' from 'D:\python3\lib\re.py'>
    # print(re.findall)
    # print(modules['re'].findall)
    
    # a = 1
    # b = 2
    # while True:
    #     name = input('变量名 :')
    #     print(__name__)
    #     print(getattr(modules[__name__],name))
    
    # '__main__': <module '__main__' from 'D:/PyCharmProject/s20/day23/5.反射.py'>
    # print(a,b)
    # print(modules['__main__'].a)
    # print(modules['__main__'].b)
    #
    # print(getattr(modules['__main__'], 'a'))
    # print(getattr(modules['__main__'], 'b'))

        4.3.5 总结

    # hasattr和getattr
        # 只要是a.b这种结构,都可以使用反射
        # 用对象类模块反射,都只有以下场景
        # 这种结构有两种场景
        #     a.b   b是属性或者变量值
        #         getattr(a,'b')   == a.b
        #     a.b()  b是函数或者方法
        #         a.b()
        #             getattr(a,'b')()
        #         a.b(arg1,arg2)
        #             getattr(a,'b')(arg1,arg2)
        #         a.b(*args,**kwargs)
        #             getattr(a,'b')(*args,**kwargs)
        # 如果是本文件中的内容,不符合a.b这种结构
            # 直接调用func()
                # getattr(sys.modules[__name__],'func')()
            # 直接使用类名 Person()
                # getattr(sys.modules[__name__],'Person')()
            # 直接使用变量名 print(a)
                # getattr(sys.modules[__name__],'a')
        # 所有的getattr都应该和hasattr一起使用
            # if hasattr():
                 getattr()
    # setattr 只用来修改或者添加属性变量,不能用来处理函数或者是其他方法
        # a.b = value
        # setattr(a,'b',value)
        
    # delattr 只用来删除 属性变量
        # del a.b 删除属性  相当于删除了a对象当中的b属性
        # delattr(a,'b')
  • 相关阅读:
    使用CustomValidate自定义验证控件
    C#中金额的大小写转换
    Andriod出错之Unable to build: the file dx.jar was not loaded from the SDK folder!
    VC 编写的打字练习
    机房工作笔记Ping只有单向通
    web服务协同学习笔记(1)
    Dll 学习3 将MDI子窗口封装在DLL中
    机房工作学习文件共享
    Andriod出错之Failed to find an AVD compatible with target 'Android 2.2'
    Andriod出错之wrapper was not properly loaded first
  • 原文地址:https://www.cnblogs.com/smithpath/p/10614764.html
Copyright © 2011-2022 走看看