反射

python 面向对象中的反射:通过字符串的形式操作对象相关的属性。python 中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
对对象的反射

  1. class Foo:
  2. f = '类的静态变量'
  3. def __init__(self,name,age):
  4. self.name=name
  5. self.age=age
  6. def say_hi(self):
  7. print('hi,%s'%self.name)
  8. obj=Foo('陈松',73)
  9. # 检测是否含有某属性
  10. print(hasattr(obj,'name'))
  11. print(hasattr(obj,'say_hi'))
  12. # 获取属性
  13. n=getattr(obj,'name')
  14. print(n)
  15. func=getattr(obj,'say_hi')
  16. func()
  17. print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
  18. # 设置属性
  19. setattr(obj,'sb',True)
  20. setattr(obj,'show_name',lambda self:self.name+'sb')
  21. print(obj.__dict__)
  22. print(obj.show_name(obj))
  23. # 删除属性
  24. delattr(obj,'age')
  25. delattr(obj,'show_name')
  26. # delattr(obj,'show_name111') # 不存在,则报错
  27. print(obj.__dict__)

Python
Copy
对类的反射

  1. class Foo(object):
  2. staticField = "test"
  3. def __init__(self):
  4. self.name = '陈松'
  5. def func(self):
  6. return 'func'
  7. @staticmethod
  8. def bar():
  9. return 'bar'
  10. print(getattr(Foo, 'staticField'))
  11. print(getattr(Foo, 'func'))
  12. print(getattr(Foo, 'bar'))

Python
Copy
当前模块的反射

  1. import sys
  2. def s1():
  3. print('s1')
  4. def s2():
  5. print('s2')
  6. this_module = sys.modules[__name__]
  7. print(hasattr(this_module, 's1'))
  8. print(getattr(this_module, 's2'))

Python
Copy
其他模块的反射

  1. 程序目录:
  2. module_test.py
  3. test.py
  4. 当前文件:
  5. test.py
  1. import module_test as obj
  2. obj.test()
  3. print(hasattr(obj,'test'))
  4. getattr(obj,'test')()

Python
Copy
举例:
使用反射前

  1. class User:
  2. def login(self):
  3. print('欢迎来到登录页面')
  4. def register(self):
  5. print('欢迎来到注册页面')
  6. def save(self):
  7. print('欢迎来到存储页面')
  8. while 1:
  9. choose = input('>>>').strip()
  10. if choose == 'login':
  11. obj = User()
  12. obj.login()
  13. elif choose == 'register':
  14. obj = User()
  15. obj.register()
  16. elif choose == 'save':
  17. obj = User()
  18. obj.save()

Python
Copy
用了反射之后

  1. class User:
  2. def login(self):
  3. print('欢迎来到登录页面')
  4. def register(self):
  5. print('欢迎来到注册页面')
  6. def save(self):
  7. print('欢迎来到存储页面')
  8. user = User()
  9. while 1:
  10. choose = input('>>>').strip()
  11. if hasattr(user, choose):
  12. func = getattr(user, choose)
  13. func()
  14. else:
  15. print('输入错误。。。。')

Python
Copy

函数 vs 方法

通过打印函数 (方法) 名确定

  1. def func():
  2. pass
  3. print(func)
  4. class A:
  5. def func(self):
  6. pass
  7. print(A.func)
  8. obj = A()
  9. print(obj.func)

Python
Copy

通过 types 模块验证

  1. from types import FunctionType
  2. from types import MethodType
  3. def func():
  4. pass
  5. class A:
  6. def func(self):
  7. pass
  8. obj = A()
  9. print(isinstance(func,FunctionType))
  10. print(isinstance(A.func,FunctionType))
  11. print(isinstance(obj.func,FunctionType))
  12. print(isinstance(obj.func,MethodType))

Python
Copy

静态方法是函数

  1. from types import FunctionType
  2. from types import MethodType
  3. class A:
  4. def func(self):
  5. pass
  6. @classmethod
  7. def func1(self):
  8. pass
  9. @staticmethod
  10. def func2(self):
  11. pass
  12. obj = A()
  13. # 静态方法其实是函数
  14. print(isinstance(A.func2,FunctionType))
  15. print(isinstance(obj.func2,FunctionType))

Python
Copy

函数与方法的区别

那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。

  1. 函数的是显式传递数据的。如我们要指明为 len() 函数传递一些要处理数据。
  2. 函数则跟对象无关。
  3. 方法中的数据则是隐式传递的。
  4. 方法可以操作类内部的数据。
  5. 方法跟对象是关联的。如我们在用 strip() 方法是,是不是都是要通过 str 对象调用,比如我们有字符串 s, 然后 s.strip() 这样调用。是的,strip() 方法属于 str 对象。

我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
在其他语言中,如 Java 中只有方法,C 中只有函数,C++ 么,则取决于是否在类中

双下方法

__len__

  1. class B:
  2. def __len__(self):
  3. return 666
  4. b = B()
  5. print(len(b)) # len 一个对象就会触发 __len__方法。
  6. class A:
  7. def __init__(self):
  8. self.a = 1
  9. self.b = 2
  10. def __len__(self):
  11. return len(self.__dict__)
  12. a = A()
  13. print(len(a))

Python
Copy

__hash__

  1. class A:
  2. def __init__(self):
  3. self.a = 1
  4. self.b = 2
  5. def __hash__(self):
  6. return hash(str(self.a)+str(self.b))
  7. a = A()
  8. print(hash(a))

Python
Copy

__str__

如果一个类中定义了 str 方法,那么在打印 对象 时,默认输出该方法的返回值。

  1. class A:
  2. def __init__(self):
  3. pass
  4. def __str__(self):
  5. return '陈松'
  6. a = A()
  7. print(a)
  8. print('%s' % a)

Python
Copy

__repr__

如果一个类中定义了 repr 方法,那么在 repr(对象) 时,默认输出该方法的返回值。

  1. class A:
  2. def __init__(self):
  3. pass
  4. def __repr__(self):
  5. return '陈松'
  6. a = A()
  7. print(repr(a))
  8. print('%r'%a)

Python
Copy

__call__

对象后面加括号,触发执行。
注:构造方法 new 的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

  1. class Foo:
  2. def __init__(self):
  3. print('__init__')
  4. def __call__(self, *args, **kwargs):
  5. print('__call__')
  6. obj = Foo() # 执行 __init__
  7. obj() # 执行 __call__

Python
Copy

__eq__

  1. class A:
  2. def __init__(self):
  3. self.a = 1
  4. self.b = 2
  5. def __eq__(self,obj):
  6. if self.a == obj.a and self.b == obj.b:
  7. return True
  8. a = A()
  9. b = A()
  10. print(a == b)

Python
Copy

__del__

析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为 Python 是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给 Python 解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

__new__

  • __new__() 方法是在类准备将自身实例化时调用。
  • __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
  • 通常来说,新式类开始实例化时,__new__()方法会返回 cls(cls 指代当前类)的实例,然后该类的__init__()方法作为构造方法会接收这个实例(即 self)作为自己的第一个参数,然后依次传入__new__()方法中接收的位置参数和命名参数。
    1. class A:
    2. def __init__(self):
    3. self.x = 1
    4. print('in init function')
    5. def __new__(cls, *args, **kwargs):
    6. print('in new function')
    7. return object.__new__(A, *args, **kwargs)
    8. a = A()
    9. print(a.x)
    Python
    Copy
    单例模式
    1. class A:
    2. __instance = None
    3. def __new__(cls, *args, **kwargs):
    4. if cls.__instance is None:
    5. obj = object.__new__(cls)
    6. cls.__instance = obj
    7. return cls.__instance
    Python
    Copy
    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
    【采用单例模式动机、原因】
    对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或 ID(序号) 生成器。如在 Windows 中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
    如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
    【单例模式优缺点】
    【优点】
    一、实例控制
    单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
    二、灵活性
    因为类控制了实例化过程,所以类可以灵活更改实例化过程。
    【缺点】
    一、开销
    虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
    二、可能的开发混淆
    使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用 new 关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
    三、对象生存期
    不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework 的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

    __item__系列

    1. class Foo:
    2. def __init__(self,name):
    3. self.name=name
    4. def __getitem__(self, item):
    5. print(self.__dict__[item])
    6. def __setitem__(self, key, value):
    7. self.__dict__[key]=value
    8. print('赋值成功')
    9. def __delitem__(self, key):
    10. print('del obj[key]时,我执行')
    11. self.__dict__.pop(key)
    12. def __delattr__(self, item):
    13. print('del obj.key时,我执行')
    14. self.__dict__.pop(item)
    15. f1=Foo('sb')
    16. f1['age']=18
    17. f1['age1']=19
    18. del f1.age1
    19. del f1['age']
    20. f1['name']='mingzi'
    21. print(f1.__dict__)
    Python
    Copy

    上下文管理器相关

    __enter__ __exit__
    1. class A:
    2. def __init__(self, text):
    3. self.text = text
    4. def __enter__(self): # 开启上下文管理器对象时触发此方法
    5. self.text = self.text + '您来啦'
    6. return self # 将实例化的对象返回f1
    7. def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法
    8. self.text = self.text + '这就走啦'
    9. with A('大爷') as f1:
    10. print(f1.text)
    11. print(f1.text)
    Python
    Copy
    自定义文件管理器
    1. class Diycontextor:
    2. def __init__(self, name, mode):
    3. self.name = name
    4. self.mode = mode
    5. def __enter__(self):
    6. print("Hi enter here!!")
    7. self.filehander = open(self.name, self.mode)
    8. return self.filehander
    9. def __exit__(self,*args):
    10. print("Hi exit here")
    11. self.filehander.close()
    12. with Diycontextor('config', 'r') as f:
    13. for i in f:
    14. print(i.strip())
    Python
    Copy
    案例
    1. class StarkConfig:
    2. def __init__(self, num):
    3. self.num = num
    4. def run(self):
    5. self()
    6. def __call__(self, *args, **kwargs):
    7. print(self.num)
    8. class RoleConfig(StarkConfig):
    9. def __call__(self, *args, **kwargs):
    10. print(345)
    11. def __getitem__(self, item):
    12. return self.num[item]
    13. v1 = RoleConfig('abcedf')
    14. v2 = StarkConfig('2333')
    15. print(v1[3])
    16. # print(v2[2])
    17. v1.run()
    Python
    Copy
    1. class UserInfo:
    2. pass
    3. class Department:
    4. pass
    5. class StarkConfig:
    6. def __init__(self, num):
    7. self.num = num
    8. def changelist(self, request):
    9. print(self.num, request)
    10. def run(self):
    11. self.changelist(999)
    12. class RoleConfig(StarkConfig):
    13. def changelist(self, request):
    14. print(666, self.num)
    15. class AdminSite:
    16. def __init__(self):
    17. self._registry = {}
    18. def register(self, k, v):
    19. self._registry[k] = v
    20. site = AdminSite()
    21. site.register(UserInfo, StarkConfig)
    22. # 1
    23. obj = site._registry[UserInfo]()
    24. # 2
    25. # obj = site._registry[UserInfo](100)
    26. obj.run()
    Python
    Copy
    1. class UserInfo:
    2. pass
    3. class Department:
    4. pass
    5. class StarkConfig:
    6. def __init__(self,num):
    7. self.num = num
    8. def changelist(self,request):
    9. print(self.num,request)
    10. def run(self):
    11. self.changelist(999)
    12. class RoleConfig(StarkConfig):
    13. def changelist(self,request):
    14. print(666,self.num)
    15. class AdminSite:
    16. def __init__(self):
    17. self._registry = {}
    18. def register(self,k,v):
    19. self._registry[k] = v(k)
    20. site = AdminSite()
    21. site.register(UserInfo,StarkConfig)
    22. site.register(Department,RoleConfig)
    23. for k,row in site._registry.items():
    24. row.run()
    Python
    Copy
    1. class A:
    2. list_display = []
    3. def get_list(self):
    4. self.list_display.insert(0, 33)
    5. return self.list_display
    6. s1 = A()
    7. print(s1.get_list())
    Python
    Copy
    1. class A:
    2. list_display = [1, 2, 3]
    3. def __init__(self):
    4. self.list_display = []
    5. def get_list(self):
    6. self.list_display.insert(0, 33)
    7. return self.list_display
    8. s1 = A()
    9. print(s1.get_list())
    Python
    Copy
    1. class A:
    2. list_display = []
    3. def get_list(self):
    4. self.list_display.insert(0,33)
    5. return self.list_display
    6. class B(A):
    7. list_display = [11,22]
    8. s1 = A()
    9. s2 = B()
    10. print(s1.get_list())
    11. print(s2.get_list())