第十一章 面向对象进阶

1.反射                                                        

1.什么叫反射

反射就是通过字符串数据类型的变量名来访问变量的值

像x.y这样的形式,都可以用反射

# 例:
print('aaa'.startswith)
# <built-in method startswith of str object at 0x000001D949B6B500>
ret = getattr('aaa', 'startswith')
print(ret)
# <built-in method startswith of str object at 0x000001D949B6B500>

# 执行
print('aaa'.startswith('a'))
# True
print(ret('a'))
# True

2.反射的类型

  对象名 反射 对象属性 和 方法

  类名 反射 静态属性

  模块 反射 模块中的名字

  反射 对自己所在文件中的名字

1) 对象名 反射 方法

# 对象名 反射 方法
class Person:
    def eat(self):print('eating')
    def drink(self):print('drinking')
    def play(self):print('playing')
    def sleep(self):print('sleepping')

alex = Person()
while True:
    inp = input('>>> ')
    # if hasattr(alex, inp):
    getattr(alex, inp)()

# >>> eat
# eating
# >>> drink
# drinking
# >>> play
# playing
# >>> sleep
# sleepping
# >>> eatt
#     getattr(alex, inp)()
# AttributeError: 'Person' object has no attribute 'eatt'

说明

1. 首先 使用getattr取获取一个名字,如果在这个对象的命名空间中没有这个名字,会报错
2. 这时候就引入了getattr的反射好伴侣hasattr
3. 如果使用getattr去获取一个方法,那么只能拿到这个方法的内存地址
4. 加上括号就是执行,当然,括号里的参数可以照传不误
5. 如果获取getattr获取一个属性,那么直接使用反射就可以获取到值

引入hasattr,判断对象是否含有这个方法

# 引入了getattr的反射好伴侣hasattr,判断对象是否含有这个方法
class Person:
    def eat(self):print('eating')
    def drink(self):print('drinking')
    def play(self):print('playing')
    def sleep(self):print('sleepping')

alex = Person()
while True:
    inp = input('>>> ')
    if hasattr(alex, inp):
        getattr(alex, inp)()
# >>> eat
# eating
# >>> eatt

2) 对象名 反射 对象属性

class Person:
    def __init__(self,name):
        self.name = name
    def eat(self):print('eating')
    def drink(self):print('drinking')
    def play(self):print('playing')
    def sleep(self):print('sleepping')

alex = Person('alex')
print(getattr(alex, 'name'))
# alex

3) 类名 反射 静态属性

class Person:
    role = '静态属性'

print(getattr(Person, 'role'))
# 静态属性

4) 模块 反射 模块中的名字

'''
mo.py文件
money = 100
def func1():
    print('in func1')

class Manager:
    def eat(self):
        print('eating')
'''

import mo
import time
print(mo.money)
# 100
# 反射模块中的变量
print(getattr(mo, 'money'))
# 100
mo.func1()
# in func1
# 括号内接参数
getattr(time, 'sleep')(0.5)
# 反射模块中的函数名
getattr(mo, 'func1')()
# in func1

# 反射模块中的类名
Manager = getattr(mo, 'Manager')
print(Manager)
# <class 'mo.Manager'>
a = Manager()
a.eat()
# eating

5) 反射自己所在文件中的名字

# 思路:找自己的文件名
value = '123'
import sys
print(sys.modules['__main__'])
print(getattr(sys.modules['__main__'], 'value'))

2.isinstance和issubclass                                     

# isinstance()
class Foo:
    pass

obj = Foo()
print(isinstance(obj, Foo))
# True
# 说明:isinstance(obj, cls) 检查obj是否是类的对象

# issubclass()
class Foo:
    pass

class Son(Foo):
    pass

print(issubclass(Son, Foo))
# True
# 说明:issubclass(Son, Foo) 检查Son类是否是Foo类的子类

3.__new__                                                    

# __new__   构造方法、创建一个对象
# __init__  初始化方法

class Foo:
    def __new__(cls, *args, **kwargs): #self还没有创建
        print('执行我啦')
        return object.__new__(cls) #-->self
    def __init__(self):
        print('2222222')

Foo()
# 执行我啦
# 2222222

# 说明:先执行new方法,object.__new__
# 再执行__init__
# #
# Foo() --> python解释器接收到你的python代码
# python解释器替你去做了很多操作
# 包括 主动帮助你 调用 new方法 去创造一个对象 -- 开辟内存空间 -- python语言封装了开辟内存的工作
# object的new方法里 -- 帮你创造了对象
# 调用init的用到的self参数,就是new帮你创造的对象

单例模式

# 什么叫单例模式
# 单例模式 : 某一类 只有一个实例

class Person:
    __isinstance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__isinstance :
            obj = object.__new__(cls)
            cls.__isinstance = obj
        return cls.__isinstance
    def __init__(self,name):
        self.name = name

alex = Person('alex')
alex.age = 18
egon = Person('egon')
print(egon.age)
# 18
print(id(alex))
# 2550191724752
print(id(egon))
# 2550191724752
print(alex.name)
# egon
print(egon.name)
# egon

# __new__生孩子
# 类 : 生一个小孩__new__ 给这个小孩穿衣服 __init__
# 单例模式下的类 : 只有一个小孩,只有内部的属性变了,孩子没变

4.__len__                                                    

class A:
    def __len__(self):
        return 10

a = A()
print(len(a))
# 10
class A:
    pass
a = A()
print(len(a))
    # print(len(a))
# TypeError: object of type 'A' has no len()

5.__str__和__repr__                                          

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    # def __str__(self):
    #     return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

# 1- 改变对象的字符串显示__str__,__repr__
s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
# from repr:  School(oldboy1,北京)
print('from str: ',str(s1))
# from str:  (oldboy1,北京)
print(s1)
# (oldboy1,北京)
# 将__str__注释后的结果为__repr__的格式化结果
# School(oldboy1,北京)

# 说明:str函数或者print函数--->obj.__str__()
# repr或者交互式解释器--->obj.__repr__()
# 如果__str__没有被定义,那么就会使用__repr__来代替输出
# 注意:这俩方法的返回值必须是字符串,否则抛出异常

# 2- format自定义格式化字符串
print(format(s1,'nat'))
# oldboy1-北京-私立
print(format(s1,'tna'))
# 私立:oldboy1:北京
print(format(s1,'tan'))
# 私立/北京/oldboy1
print(format(s1,'asfdasdffd'))
# oldboy1-北京-私立

%s和%r

class B:

    def __str__(self):
        return 'str : class B'

    def __repr__(self):
        return 'repr : class B'


b = B()
print('%s' % b)
# str : class B
print('%r' % b)
# repr : class B

6.其他方法                                                   

class Person:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return 'a object of Person named %s'%self.name
    def __hash__(self):
        return 1231212
    def __len__(self):
        return 10
a = Person('alex')
b = Person('egon')
# print(len(a))
# print(hash(a))
print(a)
# a object of Person named alex
print(b)
# a object of Person named egon
print(len(a))
# 10
print(hash(a))
# 1231212
print(len(b))
# 10
print(hash(b))
# 1231212
# 说明:类中的内置方法很多都和内置函数相关

原文地址:https://www.cnblogs.com/gongniue/p/9071744.html