• Python学习日记(二十七) 反射和几个内置函数


    isinstance()

    判断isinstance(obj,cls)中obj是否是cls类的对象

    class Person:
        def __init__(self,name):
            self.name = name
    p = Person('Jane')
    print(isinstance(p,Person))       #True

    issubclass()

    判断issubclass(sub,super)中sub是否是super类的派生类

    class Person:
        def __init__(self,name):
            self.name = name
    class Father(Person):
        pass
    print(issubclass(Father,Person))    #True
    print(issubclass(Person,Father))    #False

    反射

    反射就是用字符串类型的名字去操作变量,python中的一切事物皆为对象(都可以使用反射)

    1.hasattr()

    函数用于判断对象是否包含对应的属性,通常和getattr一起搭配使用,先用hasattr判断是否这个对象含有这个属性,如果有就通过getattr来拿值,如果没有就提示没有这个属性

    class Person:
        age = 20
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.weight = weight
        def fuc(self):
            print('weight...height...')
    #1
    if hasattr(Person,'age'):
        print(getattr(Person,'age'))          #20
    else:
        print('没有这个类属性!')
    #2
    p = Person('Adson',1.6,75)
    if hasattr(p,'bmi'):
        print(getattr(p,'bmi'))
    else:
        print('没有这个属性!')                #没有这个属性!
    #3
    if hasattr(p,'fuc'):
        getattr(p,'fuc')()                   #weight...height...
    else:
        print('没有这个方法!')

    2.getattr()

    函数用于返回一个对象属性值

    (1)反射对象的属性

    class A:
        def __init__(self,name):
            self.name = name
    a = A('Adson')
    ret = getattr(a,'name')
    print(ret)                      #Adson

    (2)反射对象的方法

    class A:
        def fuc(self):
            print('This is fuc!')
    a = A()
    ret = getattr(a,'fuc')
    print(ret)                  #<bound method A.fuc of <__main__.A object at 0x00000000024E1C88>>  获得一个绑定方法的地址
    ret()                       #This is fuc!   在ret后加上括号去调用方法

    (3)反射类的属性

    class A:
        age = 18
    ret = getattr(A,'age')
    print(ret)                 #18

    (4)反射类的方法(classmethod、staticmethod)

    一般的调用方式是类名.方法名

    class A:
        @classmethod
        def fuc(cls):
            print('This is class fuc!')
    ret = getattr(A,'fuc')
    print(ret)              #<bound method A.fuc of <class '__main__.A'>>  获得一个绑定方法
    ret()                   #This is class fuc!
    getattr(A,'fuc')()      #This is class fuc! 简写

    (5)反射模块的变量

    先建立一个模块,模块名pyfile.py,增加一个变量

    dic = {'apple' : 18,'banana' : 20}

    然后通过我的模块反射pyfile模块的变量

    import pyfile
    print(pyfile.dic)                        #{'apple': 18, 'banana': 20}
    ret = getattr(pyfile,'dic')
    print(ret)                               #{'apple': 18, 'banana': 20}

    (6)反射模块的方法

    先建立一个模块,模块名pyfile.py,增加一个方法

    def fuc():
        print('abc123aaa!!!')

    然后通过我的模块反射pyfile模块方法

    import pyfile
    ret = getattr(pyfile,'fuc')
    print(ret)                             #<function fuc at 0x0000000002498D08>
    ret()                                  #abc123aaa!!!
    getattr(pyfile,'fuc')()                #abc123aaa!!!

    (7)反射模块的类

    先建立一个模块,模块名pyfile.py,增加一个类

    class B:
        price = 200
        def __init__(self,name):
            self.name = name
        def fuc(self):
            print('This classB fuc..' + self.name)

    然后通过我的模块反射pyfile模块方法

    import pyfile
    b = getattr(pyfile,'B')('Josn')            #getattr相当于拿到了这个模块的B类 并进行实例化了一个b对象
    print(b.__dict__)                          #{'name': 'Josn'}
    print(b.price)                             #200
    b.fuc()                                    #This classB fuc..Josn

    (8)反射自身模块的变量

    通过sys.modules['__main__']找到当前的模块

    import time
    import sys
    t = time.asctime(time.localtime(time.time()))
    print(t)                                        #Mon Sep  9 22:36:40 2019
    print(sys.modules['__main__'])                  #<module '__main__' from 'C:/Users/Administrator/PycharmProjects/PYL/temp_file/temp_py.py'>
    print(sys.modules['__main__'].t)                #Mon Sep  9 22:38:01 2019
    ret = getattr(sys.modules['__main__'],'t')
    print(ret)                                      #Mon Sep  9 22:39:05 2019

    (9)反射自身模块的方法

    import sys
    def fuc():
        print('abc123...')
    ret = getattr(sys.modules['__main__'],'fuc')
    print(ret)                                    #<function fuc at 0x0000000002798730>
    ret()                                         #abc123...
    getattr(sys.modules['__main__'],'fuc')()      #abc123...

    3.setattr()

    用于设置属性值,该属性不一定是存在的

    class Person:
        age = 20
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.weight = weight
    #对一个对象修改
    p = Person('Adson',1.6,75)
    setattr(p,'name','Jane')
    setattr(p,'height',1.7)
    setattr(p,'gender','male')
    print(p.__dict__)                   #{'name': 'Jane', 'height': 1.7, 'weight': 75, 'gender': 'male'}
    #对一个类修改
    print(Person.__dict__)              #{'__module__': '__main__', 'age': 20, '__init__': <function Person.__init__ at 0x0000000002548950>,
                           '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__':
                           <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    setattr(Person,'age',21) setattr(Person,'name','Jane') setattr(Person,'height',1.7) setattr(Person,'gender','male') print(Person.__dict__) #{'__module__': '__main__', 'age': 21, '__init__': <function Person.__init__ at 0x0000000002548950>,
                           '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__':
                           <attribute '__weakref__' of 'Person' objects>, '__doc__': None,
                           'name': 'Jane', 'height': 1.7, 'gender': 'male'}

    这里的不同之处在于对象和类它们存放值的命名空间不同

    4.delattr()

    用于删除属性

    class Person:
        age = 20
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.weight = weight
    p = Person('Adson',1.6,75)
    print(p.__dict__)                   #{'name': 'Adson', 'height': 1.6, 'weight': 75}
    delattr(p,'height')
    print(p.__dict__)                   #{'name': 'Adson', 'weight': 75}
    print(Person.__dict__['age']) #20 delattr(Person,'age') print(Person.__dict__['age']) #KeyError: 'age'

    内置类方法

    内置的类方法和内置函数之间有着千丝万缕的关系

    1.__str__

    当我们定义一个类,并实例化一个对象,再对这个对象去print

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
    a = A('AAA',200,'A')
    print(str(a))                       #<__main__.A object at 0x00000000020D7A58>

    这里返回了这个对象的内存地址,我们再在A类里面添加一个__str__方法,看一看结果是什么

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __str__(self):
            return 'name = %s,price = %s,types = %s'%(self.name,self.price,self.types)
    a = A('AAA',200,'A')
    print(a)                        #name = AAA,price = 200,types = A   

    可以这么说我们在每次打印一个对象的时候就是在调用obj.__str__,且__str__方法需要返回一个字符串,当做这个类的描写;当我们使用print这个对象时会打印出__str__方法return出来的字符串

    2.__repr__

    先说一下repr()方法,它能让我们输入的数据原形毕露

    print(repr(1))                  #1
    print(repr('1'))                #'1'
    print(repr('aaa'))              #'aaa'
    print(repr({'a':1,'b':2}))      #{'a': 1, 'b': 2}

    和__str__一样我们在定义一个类后去print它实例化的对象,会获得到一个对象的内存地址

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
    a = A('AAA',200,'A')
    print(repr(a))                 #<__main__.A object at 0x00000000024E7A58>

    然后我们再在A中添加__repr__方法看一下print的结果

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __repr__(self):
            return 'name = %s,price = %s,types = %s' % (self.name, self.price, self.types)
    a = A('AAA',200,'A')
    print(repr(a))                   #name = AAA,price = 200,types = A
    print(a)                         #name = AAA,price = 200,types = A

    因为我们在类中定义了一个__repr__方法,这里我们print对象a的时候就相当于是调用了里面的__repr__方法即a.__repr__

    如果一个类中的__str__和__repr__同时存在的话,那么最后的打印结果是什么呢?

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __str__(self):
            return 'str(name = %s,price = %s,types = %s)'%(self.name,self.price,self.types)
        def __repr__(self):
            return 'repr(name = %s,price = %s,types = %s)' % (self.name, self.price, self.types)
    a = A('AAA',200,'A')
    print(repr(a))                            #repr(name = AAA,price = 200,types = A)   即a.__repr__
    print('%r'%a)                             #repr(name = AAA,price = 200,types = A)
    print(str(a))                             #str(name = AAA,price = 200,types = A)    即a.__str__
    print('%s'%a)                             #str(name = AAA,price = 200,types = A)
    print(a)                                  #str(name = AAA,price = 200,types = A)

    如果一个类中__str__方法,那么它就会先找__str__,没有的话就再找__repr__方法,再没有的话就会找它父类的__str__方法

    __str__方法和__repr__方法能够返回该对象一个规范化的信息

    3.__len__

    我们将一个实例化的对象直接print它的len看一看会出现什么结果

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
    a = A('AAA',200,'A')
    print(len(a))           #TypeError: object of type 'A' has no len()

    结果报错说A少了一个len函数,也就是我们只有在A中加上一个__len__的方法才能去计算长度相关的东西

    计算属性的长度:

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __len__(self):
            return len(self.name)
    a = A('AAA',200,'A')
    print(len(a))                            #3

    计算一个列表属性有几个元素:

    class A:
        def __init__(self,goods = []):
            self.goods = []
        def __len__(self):
            return len(self.goods)
    a = A()
    print(len(a))                            #0
    a.goods.append('Banana')
    a.goods.append('Apple')
    a.goods.append('Orange')
    a.goods.append('Pear')
    print(len(a))                            #4

    4.__call__

    用于打印这个对象的属性

    class A:
        gender = 'male'
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __call__(self, *args, **kwargs):
            return self.name,self.price,self.types,self.gender
    a = A('AAA',200,'A')
    print(a())                      #('AAA', 200, 'A', 'male')
    print(A('AAA',200,'A')())       #('AAA', 200, 'A', 'male')

    5.__eq__

    class A:
        __instance = False
        def __init__(self,name,age,height):
            self.name = name
            self.age = age
            self.height = height
        def __eq__(self, other):
            if self.name == other.name and self.height == other.height:
                return True
            else:
                return False
    a1 = A('Jane',20,55)
    a2 = A('Jane',18,55)
    print(a1 == a2)     #True

    6.__hash__

    控制对象中的哈希值和另外一个对象的哈希值是否相等

    class A:
        def __init__(self,name,age,height):
            self.name = name
            self.age = age
            self.height = height
        def __hash__(self):
            return hash(self.age + self.height) + hash(self.name)
    a1 = A('Jane',20,55)
    a2 = A('Jane',18,55)
    print(hash(a1))         #-1393240518857837779
    print(hash(a2))         #-1393240518857837781

    7.__new__

    创建一个对象

    class A:
        height = 18
        def __init__(self):
            self.name = 'Aane'
            self.price = 300
            self.types = 'aaa'
        def __new__(cls, *args, **kwargs):
            print('实例化一个对象...')
            return object.__new__(cls, *args, **kwargs)
    a = A()                 #实例化一个对象...
    print(a.__dict__)       #{'name': 'Aane', 'price': 300, 'types': 'aaa'}

    单例模式:限制一个类始终只有一个实例,因为一般来讲一个类可以产生无数个对象

    在这里我们创建三个对象并打印它们的内存地址可以发现它们是不同的

    class A:
        def __init__(self):
            self.name = 'aaa'
    a1 = A()
    a2 = A()
    a3 = A()
    print(a1)   #<__main__.A object at 0x00000000025B1D68>
    print(a2)   #<__main__.A object at 0x00000000025CD0F0>
    print(a3)   #<__main__.A object at 0x00000000025CD128>

    所以在我们第一次实例化这个类的时候就创建一个实例化的对象,那么我们再一次实例化一个对象的话该如何再去使用之前的实例化对象呢?

    class A:
        __instance = False
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __new__(cls,*args,**kwargs):
            if cls.__instance:
                return cls.__instance
            cls.__instance = object.__new__(A)
            return cls.__instance
    a1 = A('Jogn',33)
    a2 = A('Jane',35)
    a3 = A('KKK',55)
    print(a1)                       #<__main__.A object at 0x000000000217D198>
    print(a1.__dict__)              #{'name': 'KKK', 'age': 55}
    print(a2)                       #<__main__.A object at 0x000000000217D198>
    print(a2.__dict__)              #{'name': 'KKK', 'age': 55}
    print(a3)                       #<__main__.A object at 0x000000000217D198>
    print(a3.__dict__)              #{'name': 'KKK', 'age': 55}
    print(id(a1),id(a2),id(a3))     #41734552 41734552 41734552

    8.__del__

    析构函数:当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数,它往往用来做"清理善后"的工作。当我们直接删除一个实例化的对象再去打印它,就会报错告诉我们这个对象已经不存在了

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
    a = A('AAA',200,'A')
    del a
    print(a)    #NameError: name 'a' is not defined

    我们再在A中添加一个__del__方法

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __del__(self):
            print('这个对象%s已被删除!' % self.name)
            del self
    a = A('AAA',200,'A')
    del a       #这个对象AAA已被删除!   这里相当于调用了a.__dict__
    print(a)    #NameError: name 'a' is not defined

    8.__getitem__

    模拟字典的方式来拿值

    class A:
        gender = 'male'
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __getitem__(self, item):
            if hasattr(self,item):
                return getattr(self,item)
            return '没有找到这个值!'
    a = A('AAA',200,'A')
    print(a['name'])        #AAA
    print(a['price'])       #200
    print(a['types'])       #A
    print(a['gender'])      #male
    print(a['sex'])         #没有找到这个值!

    9.__setitem__

    模拟字典的方式来设值

    class A:
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __setitem__(self,key,value):        #重新设定一个新的值
            self.__dict__['key'] = value
    a = A('AAA',200,'A')
    print(a.__dict__)                           #{'name': 'AAA', 'price': 200, 'types': 'A'}
    a.__dict__['name'] = 'BBB'
    a.__dict__['price'] = 300
    a.__dict__['types'] = 'C'
    a.__dict__['gender'] = 'male'               #增加了一个新的属性gender
    print(a.__dict__)                           #{'name': 'BBB', 'price': 300, 'types': 'C', 'gender': 'male'}

    10.__delitem__

    模拟字典的方式来删除

    class A:
        gender = 'male'
        def __init__(self,name,price,types):
            self.name = name
            self.price = price
            self.types = types
        def __delitem__(self, key):
            print('%s已删除!'%key)
            del self.__dict__[key]
    a = A('AAA',200,'A')
    del a['name']       #name已删除!
    del a['price']      #price已删除!
    print(a.__dict__)   #{'types': 'A'}

    问题总结

    1.有很多对象,它们的姓名和性别相同但是年龄不同,如何这种情况的对象去重?

    class A:
        def __init__(self,name,sex,age):
            self.name = name
            self.sex = sex
            self.age = age
        def __eq__(self, other):
            if self.name == other.name and self.sex == other.sex:
                return True
            return False
        def __hash__(self):
            return hash(self.name+self.sex)
    a = A('Json','male',26)
    b = A('Json','male',30)
    print(set((a,b)))   #set()依赖对象的 __eq__和__hash__ {<__main__.A object at 0x0000000002761DD8>}

    2.扑克牌问题

    import json
    from collections import namedtuple
    Card = namedtuple('Card',['rank','suit'])   #rank牌面的大小 suit牌面的花色
    class FrenchDeck:
        ranks = [str(n) for n in range(2,11)] + list('JQKA')
        suits = ['红心','方块','梅花','黑桃']
        def __init__(self):
            self._cards = [Card(rank,suit) for rank in FrenchDeck.ranks for suit in FrenchDeck.suits]
    
        def __len__(self):
            return len(self._cards)
    
        def __getitem__(self, item):
            return self._cards[item]
    
        def __setitem__(self,key,value):
            self._cards[key] = value
    
        def __str__(self):
            return json.dumps(self._cards,ensure_ascii=False)
    
    deck = FrenchDeck()
    print(deck[10])         #Card(rank='4', suit='梅花')
    from random import choice
    print(choice(deck))     #Card(rank='3', suit='方块')
    print(choice(deck))     #Card(rank='9', suit='方块')
    from random import shuffle
    shuffle(deck)
    print(deck[10])         #Card(rank='2', suit='方块')
    print(deck)             #打印所有牌色
    print(deck[:5])         #[Card(rank='6', suit='梅花'), Card(rank='3', suit='方块'), Card(rank='10', suit='红心'),
                  #Card(rank='9', suit='红心'), Card(rank='4', suit='方块')]
  • 相关阅读:
    配置FTP服务2(vsftpd 配置虚拟账号)
    配置FTP服务(pure-ftpd安装配置测试)
    asp.net学习——Repeater控件
    C#方法,属性,和事件
    (转)AspNetPager使用方法
    WebForms UnobtrusiveValidationMode 需要“jquery”ScriptResourceMapping
    SQL Server 操作数据
    SQL Server——增、删、改、查。
    数组——求和、平均分、最值
    数组——抽奖&&句子组合
  • 原文地址:https://www.cnblogs.com/Fantac/p/11495039.html
Copyright © 2020-2023  润新知