一、反射
1、什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 、python面向对象中的反射
通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)。
类名 ——反射 静态属性
对象名 ——反射 对象属性 和 方法
模块 ——反射模块中的名字
反射 ——自己所在文件中的名字
3、使用说明
首先 使用getattr取获取一个名字,如果在这个对象的命名空间中没有这个名字 会报错;
getattr的反射好伴侣 hasattr 判断在这个对象的命名空间中没有这个名字 存在返回True 否则False;
如果使用getattr取获取一个方法,那么只能拿到这个方法的内存地址 加上括号就是执行,当然,括号里的参数可以照传不误;
如果getattr获取一个属性,那么直接使用反射就可以获取到值。
模块就是一个py文件,pyi代表是内置模块;
所谓的模块导入 就是执行了这个文件而已。
4、四个可以实现自省的函数:hasattr、getattr、setattr、delattr
# 1)四个方法的使用示例 class Foo: f = '类的静态变量' def __init__(self, name, age): self.name = name self.age = age def say_hi(self): print('hi,%s' % self.name) obj = Foo('egon', 73) # 检测是否含有某属性 print(hasattr(obj, 'name')) # >>>True print(hasattr(obj, 'say_hi')) # >>>True # 获取属性 n = getattr(obj, 'name') print(n) # >>>egon func = getattr(obj, 'say_hi') func() # >>>hi,egon # print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 # 设置属性 setattr(obj, 'sb', True) setattr(obj, 'show_name', lambda self: self.name + 'sb') print( obj.__dict__) # >>>{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x00000292BAE05F28>} print(obj.show_name(obj)) # >>>egonsb # 删除属性 delattr(obj, 'age') delattr(obj, 'show_name') # delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__) # >>>{'name': 'egon', 'sb': True}
#2)类也是对象 class Foo(object): staticField = "old boy" def __init__(self): self.name = 'wupeiqi' def func(self): return 'func' @staticmethod def bar(): return 'bar' print(getattr(Foo, 'staticField')) print(getattr(Foo, 'func')) print(getattr(Foo, 'bar')) # 执行结果 # old boy # <function Foo.func at 0x000001A8F4739378> # <function Foo.bar at 0x000001A8F4739400>
# 3)反射当前模块的成员 import sys def s1(): print('s1') def s2(): print('s2') this_module = sys.modules[__name__] print(hasattr(this_module, 's1'))#>>>True getattr(this_module, 's2')()#>>>s2
# 4)示例 class Person: role = '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') alex.name print(getattr(alex, 'name')) # >>>alex print(getattr(Person, 'role')) # >>>Person while True: inp = input('>>>') if hasattr(alex, inp): getattr(alex, inp)() # 执行结果: # >>>eat # eating # >>>drink # drinking # >>>play # playing # >>>sleep # sleepping # >>>111 # >>>
# 5)反射当前模块成员 # mymodule.py # money = 100 # def func1(): # print('func1') # # def func2(): # print('func2') # # class Manager: # def eat(self): # print('eating') import mymodule import time mymodule.func1()#>>>func1 time.sleep(0.5) print(mymodule.money)#>>>100 getattr(mymodule,'func1')()#>>>func1 print(getattr(mymodule,'money'))#>>>100 getattr(time,'sleep')(1) Manager = getattr(mymodule,'Manager')#拿到一个类的内存地址 a = Manager() a.eat()#>>>eating value = '123' import sys print(sys.modules) #>>>{'builtins': <module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_thread': <module '_thread' (built-in)>, '_weakref': <module '_weakref' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'nt': <module 'nt' (built-in)>, 'winreg': <module 'winreg' (built-in)>, 'zipimport': <module 'zipimport' (built-in)>, 'encodings': <module 'encodings' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\__init__.py'>, 'codecs': <module 'codecs' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\codecs.py'>, '_codecs': <module '_codecs' (built-in)>, 'encodings.aliases': <module 'encodings.aliases' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\aliases.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\utf_8.py'>, '_signal': <module '_signal' (built-in)>, '__main__': <module '__main__' from 'C:/Users/28163/Desktop/老男孩教育-Python21期/day07/day7视频与笔记/day7笔记/9.反射.py'>, 'encodings.latin_1': <module 'encodings.latin_1' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\latin_1.py'>, 'io': <module 'io' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\io.py'>, 'abc': <module 'abc' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\abc.py'>, '_weakrefset': <module '_weakrefset' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\_weakrefset.py'>, 'site': <module 'site' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\site.py'>, 'os': <module 'os' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\os.py'>, 'errno': <module 'errno' (built-in)>, 'stat': <module 'stat' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\stat.py'>, '_stat': <module '_stat' (built-in)>, 'ntpath': <module 'ntpath' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\ntpath.py'>, 'genericpath': <module 'genericpath' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\genericpath.py'>, 'os.path': <module 'ntpath' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\ntpath.py'>, '_collections_abc': <module '_collections_abc' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\_collections_abc.py'>, '_sitebuiltins': <module '_sitebuiltins' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\_sitebuiltins.py'>, '_bootlocale': <module '_bootlocale' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\_bootlocale.py'>, '_locale': <module '_locale' (built-in)>, 'encodings.gbk': <module 'encodings.gbk' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\gbk.py'>, '_codecs_cn': <module '_codecs_cn' (built-in)>, '_multibytecodec': <module '_multibytecodec' (built-in)>, 'sysconfig': <module 'sysconfig' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\sysconfig.py'>, 'encodings.cp437': <module 'encodings.cp437' from 'C:\Users\28163\AppData\Local\Programs\Python\Python36\lib\encodings\cp437.py'>, 'sitecustomize': <module 'sitecustomize' from 'C:\Program Files\JetBrains\PyCharm 2017.3.4\helpers\pycharm_matplotlib_backend\sitecustomize.py'>, 'mymodule': <module 'mymodule' from 'C:\Users\28163\Desktop\老男孩教育-Python21期\day07\day7视频与笔记\day7笔记\mymodule.py'>, 'time': <module 'time' (built-in)>} print(sys.modules['__main__']) #>>><module '__main__' from 'C:/Users/28163/Desktop/老男孩教育-Python21期/day07/day7视频与笔记/day7笔记/9.反射.py'> print(getattr(sys.modules['__main__'],'value'))#>>>123 反射自己模块当中的名字
# 6)示例 class Manager: def __init__(self, name): self.name = name def create_course(self): pass class Teacher: def __init__(self, name): self.name = name def list_student(self): pass class Student: def __init__(self, name): self.name = name def create_course(self): pass a = Student('a') a.age = 19 setattr(a, 'age', 25) print(a.__dict__) # >>>{'name': 'a', 'age': 25} print(a.age) # >>>25 import sys # login 先进行登录 # 输入name,pwd 与文件内容比对,然后找到对应身份的类 id = 'Manager' if hasattr(sys.modules['__main__'], id): obj = getattr(sys.modules['__main__'], id)(name, pwd)
二、面向对象进阶
1、isinstance和issubclass
# 1)isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) # >>>True # 2)issubclass(sub, super)检查sub类是否是 super 类的派生类 class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) # >>>True
2、__new__
1)__new__、__init__
# __new__ 构造方法 创建一个对象 # __init__ 初始化方法 # 先执行new方法,object.new() 再执行init class Foo: def __new__(cls, *args, **kwargs): print('执行我啦') obj = object.__new__(cls) print(obj) return obj def __init__(self): print('222222222', self) Foo() # 执行结果: # >>>执行我啦 # >>><__main__.Foo object at 0x000002C2FB913A90> # >>>222222222 <__main__.Foo object at 0x000002C2FB913A90> # 执行过程: # Foo() --> python解释器接收到你的python代码 # python解释器替你去做了很多操作(翻译成C语言的字节码,将C语言的字节码解释成 机器码 让CPU去执行) # 包括 主动帮助你 调用 new方法 去创造一个对象 —— 开辟内存空间 —— python语言封装了开辟内存的工作 # object的new方法里 —— 帮你创造了对象 # 调用init用到的self参数 就是new帮你创造的对象
2)单例模式
# 单例模式 : 是一种设计模式 某一个类 只有一个实例 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) print(id(alex)) print(id(egon)) print(alex.name) print(egon.name) # 执行结果: # 18 # 2669030687800 # 2669030687800 # egon # egon
3、__str__、__repr__、__format__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
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) s1 = School('oldboy1', '北京', '私立') print('from repr: ', repr(s1)) print('from str: ', str(s1)) print(s1) # 执行结果 # >>>from repr: School(oldboy1,北京) # >>>from str: (oldboy1,北京) # >>>(oldboy1,北京) ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1, 'nat')) print(format(s1, 'tna')) print(format(s1, 'tan')) print(format(s1, 'asfdasdffd')) # 执行结果 # >>>oldboy1-北京-私立 # >>>私立:oldboy1:北京 # >>>私立/北京/oldboy1 # >>>oldboy1-北京-私立
class B: def __str__(self): return 'str : class B' def __repr__(self): return 'repr : class B' b = B() print('%s' % b) print('%r' % b) # 执行结果 # >>>ostr : class B # >>>orepr : class B
4、__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f1 = Foo() del f1 print('------->') # 输出结果 # >>>执行我啦 # >>>------->
5、item系列(__getitem__、__setitem__、__delitem__)
class Foo: def __init__(self, name): self.name = name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): self.__dict__[key] = value def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item) f1 = Foo('sb') f1['age'] = 18 f1['age1'] = 19 del f1.age1 # >>>del obj.key时,我执行 del f1['age'] # >>>del obj[key]时,我执行 f1['name'] = 'alex' print(f1.__dict__) # >>>{'name': 'alex'}
6、__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__ # 输出结果>>>__call__
7、__len__
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a)) # >>>2
8、__hash__
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self): return hash(str(self.a) + str(self.b)) a = A() print(hash(a)) # >>>1060108502313640553
9、__eq__
class A: def __init__(self): self.a = 1 self.b = 2 def __eq__(self, obj): if self.a == obj.a and self.b == obj.b: return True a = A() b = A() print(a == b) # >>>True
面试题:
#实例化n个对象 84 个 #对84个对象进行去重 # 如果两个对象的姓名和性别相同,我就认为是相同的对象 class Person: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name + self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex: return True p_lst = [] for i in range(84): p_lst.append(Person('egon', i, 'male')) print(p_lst) print(set(p_lst))