Python系列之 - 反射
一、静态方法(staticmethod)和类方法(classmethod)
类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性)
静态方法:让类里的方法直接被类调用,就像正常调用函数一样
类方法和静态方法的相同点:都可以直接被类调用,不需要实例化
类方法和静态方法的不同点:
类方法必须有一个cls参数表示这个类,可以使用类属性
静态方法不需要参数
绑定方法:分为普通方法和类方法
普通方法:默认有一个self对象传进来,并且只能被对象调用-------绑定到对象
类方法:默认有一个cls对象传进来,并且可以被类和对象(不推荐)调用-----绑定到类
非绑定方法:静态方法:没有设置默认参数,并且可以被类和对象(不推荐)调用-----非绑定
class Student: f = open('student', encoding='utf-8') def __init__(self): pass @classmethod #类方法 :有个默认参数cls,并且可以直接使用类名去 #调用,还可以与类属性交互(也就是可以使用类属性) def show_student_info_class(cls): # f = open('student', encoding='utf-8') for line in cls.f: name,sex = line.strip().split(',') print(name,sex) @staticmethod #静态方法:可以直接使用类名去调用,就像正常的函数调用一样 def show_student_info_static(): #不用传self f = open('student',encoding='utf-8') for line in f: name,sex = line.strip().split(',') print(name,sex) # egon = Student() # egon.show_student_info_static() #也可以这样调,但是还是推荐用类名去调 # egon.show_student_info_class() Student.show_student_info_class()#类名.方法名() print('-------------------') Student.show_student_info_static()#类名.方法名() staticmethod和classmethod
一、isinstance 和 issubclass
isinstance(obj,cls):检查obj是不是cls的对象(传两个参数,一个是对象,一个是类)
issubclass(sub,super):检查sub是不是super的子类(传两个参数,一个是子类,一个是父类)
class Foo: pass class Son(Foo): pass s = Son() print(isinstance(s,Son)) #判断s是不是Son的对象 print(type(s) is Son) print(isinstance(s,Foo)) #判断s是不是Foo的对象 不精准 print(type(s) is Foo) #type比较精准 print(issubclass(Son,Foo)) #判断Son是不是Foo的子类 print(issubclass(Son,object)) print(issubclass(Foo,object)) print(issubclass(int,object))
二、反射
反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。
反射有四种方法:
hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False
getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用
需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()
setattr:给对象的属性赋值,若属性不存在,先创建后赋值
delattr:删除该对象指定的一个属性
class Foo: def __init__(self): self.name = 'egon' self.age = 51 def func(self): print('hello') egg = Foo() setattr(egg,'sex','男') print(egg.sex) # 2. def show_name(self): print(self.name+'sb') setattr(egg,'sh_name',show_name) egg.sh_name(egg) show_name(egg)
delattr(egg,'name')
print(egg.name)
1.对象应用反射
class Foo:
def __init__(self):
self.name = 'egon'
self.age = 51
def func(self):
print('hello')
egg = Foo()
print(hasattr(egg,'name')) #先判断name在egg里面存在不存在
print(getattr(egg,'name')) #如果为True它才去得到
print(hasattr(egg,'func'))
print(getattr(egg,'func')) #得到的是地址
# getattr(egg,'func')() #在这里加括号才能得到,因为func是方法
if hasattr(egg,'func'):
getattr(egg,'func')()
else:
print('没找到')
1 class Foo: 2 def __init__(self): 3 self.name = 'egon' 4 self.age = 51 5 def func(self): 6 print('hello') 7 egg = Foo() 8 print(hasattr(egg,'name')) #先判断name在egg里面存在不存在 9 print(getattr(egg,'name')) #如果为True它才去得到 10 print(hasattr(egg,'func')) 11 print(getattr(egg,'func')) #得到的是地址 12 # getattr(egg,'func')() #在这里加括号才能得到,因为func是方法 13 if hasattr(egg,'func'): 14 getattr(egg,'func')() 15 else: 16 print('没找到')
2.类应用反射
class Foo:
f = 123
@classmethod
def class_method_dome(cls):
print('class_method_dome')
@staticmethod
def static_method_dome():
print('static_method_dome')
print(hasattr(Foo,'class_method_dome'))
method = getattr(Foo,'class_method_dome')
method()
print('------------')
print(hasattr(Foo,'static_method_dome'))
method1 = getattr(Foo,'static_method_dome')
method1()
1 class Foo: 2 f = 123 3 @classmethod 4 def class_method_dome(cls): 5 print('class_method_dome') 6 7 @staticmethod 8 def static_method_dome(): 9 print('static_method_dome') 10 print(hasattr(Foo,'class_method_dome')) 11 method = getattr(Foo,'class_method_dome') 12 method() 13 print('------------') 14 print(hasattr(Foo,'static_method_dome')) 15 method1 = getattr(Foo,'static_method_dome') 16 method1()
3.模块应用反射
模块的应用又分为导入其他模块反射和在本模块中反射
# 1.导入其他模块引用
import mymodule
print(hasattr(mymodule,'test'))
getattr(mymodule,'test')()
# # 这里的getattr(mymodule,'test')()这一句相当于
# p = getattr(mymodule,'test')
# p()
1 # 1.导入其他模块引用 2 import mymodule 3 print(hasattr(mymodule,'test')) 4 getattr(mymodule,'test')() 5 6 # # 这里的getattr(mymodule,'test')()这一句相当于 7 # p = getattr(mymodule,'test') 8 # p()
# 2.在本模块中应用反射
def demo1():
print('wwww')
import sys
# print(sys.modules)
module_obj = sys.modules[__name__] #相当于'__main__'
print(module_obj)
print(hasattr(module_obj,'demo1'))
getattr(module_obj,'demo1')()
# 举例 def 注册(): print('regiester') def 登录(): print('login') def 购物(): pass print('注册,登录,购物') ret = input('请输入你要做的操作:') import sys my_module = sys.modules[__name__] #利用sys模块导入一个自己的模块 if hasattr(my_module,ret): getattr(my_module,ret)() 导入自己的模块的一个简单小例子
反射补充:
db.mysql
class MySQlHelper(object): print('MySQlHelper1111111') def fetchone(self): print('你好')
db.pool
class PoolHelper(object): print('PoolHelper')
settings.py
DB_PATH = 'db.mysql.MySQlHelper' #吧字符串切割 module_name,cls_name = DB_PATH.rsplit('.',maxsplit=1) # print(module_name,cls_name) #db.mysql MySQlHelper #导入模块 # from db.mysql import MySQlHelper import importlib moudel_obj = importlib.import_module(module_name) print(moudel_obj,type(moudel_obj)) #导入模块中的类 cls = getattr(moudel_obj,cls_name) print(cls) #对类进行实例化 obj = cls() obj.fetchone() # getattr()
三、内置方法
1.__str__和__repr__
改变对象的字符串显示
class Foo: def __init__(self,name): self.name = name def __repr__(self): return 'obj in str' #这里只能是return # def __str__(self): # return '%s obj in str'%self.name f = Foo('egon') print(f) #优先执行__str__里面的内容 # 那么你是不是据地__repr__没用呢? # print('%s'%f) #执行的是__str__里面的返回值 # print('%r'%f) #执行的是__repr__里面的返回值 print('==============') print(str(f)) #当执行str(f)时,会去找__str__这个方法,如果找不到的时候,__repr__这个方法就给替补了 print(repr(f)) #1.当打印一个对象的时候,如果实现了__str__方法,打印__str__中的返回值 # 2.当__str__没有被实现的时候,就会调用__repr__方法 # 3.但是当你用字符串格式化的时候,%s和%r会分别调用__str__和__repr__方法 # 4.不管是在字符串格式化的时候还是在打印对象的时候, # __repr__方法都可以作为__str__方法的替补,但反之则不行 # 5.用于友好的表示对象。如果__str__和__repr__方法你只能实现一个:先实现__repr__ __str__和__repr__
2.__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f= Foo() print(123) print(123) print(123) print(123)
3.item系列
分别有__getitem__ ,__setitem__ ,__delitem__
class Foo: def __init__(self): self.name = 'egon' self.age = 73 self.l=[1,2,3] def __getitem__(self, item): #得到 # return self.l[item] # return self.__dict__[item] # print(Foo.__dict__) return 123 def __setitem__(self, key, value): #修改 print(key,value) self.__dict__[key] = value def __delitem__(self, key): #删除 del self.__dict__[key] f = Foo() print(f['qqq']) #不管里面放的啥值,它都会得到返回值的内容,调用的是__getitem__方法 f['name']='alex' #修改egon的值为alex,调用 __setitem__方法 # del f['name'] #删除name,就会报错了,说明在调用__delitem__方法调用成功了,就已经删了,就会报错了 print(f.name) f1 = Foo() print(f == f1) # print(f.name) # print(f[0]) #一开始不能这样取值,但是提供了一个__getitem__方法,这样就可以用了 # print(f[1]) # print(f[2]) 三个方法的使用
4.__new__(创建)
# 4.__new__方法 # 单例模式:是一种设计模式 class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance one = Singleton() two = Singleton() print(one,two) #他们两个的地址一样 one.name = 'alex' print(two.name) 单例模式
# class A: # def __init__(self): #有一个方法在帮你创造self # print('in init function') # self.x = 1 # # def __new__(cls, *args, **kwargs): # print('in new function') # return object.__new__(A, *args, **kwargs) # a = A() # b = A() # c = A() # d = A() # print(a,b,c,d) __new__
5.__call__
对象后面加括号,触发执行
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: 2 def __call__(self, *args, **kwargs): 3 print(123) 4 # f = Foo() 5 # f() #如果不写上面的__call__方法,就不会调用。如果加上,就正确了 6 Foo()() #也可以这样表示
6.__hash__
class Foo: def __hash__(self): print('aaaaaaaaaa') return hash(self.name) # print('aaas') f = Foo() f.name = 'egon' print(hash(f)) #hash方法是可以重写的 __hash__
7.__eq__
class A: def __eq__(self, other): return True a = A() b = A() print(a==b) #不加方法的时候返回的是False,加了个__eq__方法就返回了个True # '=='内部就调用了__eq__方法 print(a is b) __eq__
一道面试题
from collections import namedtuple Card = namedtuple('Card',['rank','suit']) #两个属性:一个是数,一个是花色(每一个card的对象就是一张纸牌) class FranchDeck: #纸牌数据类型 ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks #先循环这个,在循环下面的那个循环 for suit in FranchDeck.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 deck = FranchDeck() # print(deck[0]) # print(deck[0]) # print(deck[0]) # print(deck[0]) from random import choice print(choice(deck)) print(choice(deck)) from random import shuffle shuffle(deck) print(deck[:5]) 纸牌游戏