1、classmethod、staticmethod方法
classmethod类方法默认参数cls,可以直接用类名调用,可以与类属性交互
#student文件内容 宝宝,男 博博,女 海娇,男 海燕,女 海东,男 海峰,男 class Student: f = open('student', encoding='utf-8') def __init__(self): pass def func(self): pass @classmethod #类方法:默认参数cls,可以直接用类名调用,可以与类属性交互 def show_student_info_class(cls): for line in cls.f: name, sex = line.strip().split(',') print(name, sex) @staticmethod #静态方法 : 让类里的方法直接被类调用,就像正常的函数一样 def show_student_info_static(): f = open('student', encoding='utf-8') for line in f: name, sex = line.strip().split(',') print(name, sex) print(Student.show_student_info_class()) print(Student.show_student_info_static()) ''' 运行结果: 宝宝 男 博博 女 海娇 男 海燕 女 海东 男 海峰 男 None 宝宝 男 博博 女 海娇 男 海燕 女 海东 男 海峰 男 None '''
总结:
相同:都可以直接被类调用,不需要实例化,也都可以实例化然后再调用
不同:
类方法必须有一个cls参数表示这个类,可以使用类属性
静态方法不需要,静态方法不能直接使用
绑定方法
非绑定方法
普通方法 默认有一个self对象传进来,并且只能被对象调用——绑定到对象
类方法 默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用——绑定到类
静态方法 没有默认参数,并且可以被类和对象(不推荐)调用——非绑定
2.isinstance、issubclass
isinstance
判断一个对象是不是这个类的对象,传两个参数(对象,类)
class Foo: pass class Son(Foo): pass s = Son() #判断一个对象是不是这个类的对象,传两个参数(对象,类) print(isinstance(s,Son)) print(isinstance(s,Foo)) print(type(s) is Son) print(type(s) is Foo)
issubclass
class Foo: pass class Son(Foo): pass s = Son() #判断一个类是不是另一类的子类,传两个参数(子类,父类) print(issubclass(Son,Foo)) print(issubclass(Son,object)) print(issubclass(Foo,object)) print(issubclass(int,object)) ''' 输出结果: True True True True '''
一、反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
常用:
hasattr
getattr
不常用:
setattr
delattr
hasattr class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() print(hasattr(egg,'name')) #如果存在则返回一个布尔值
class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() print(getattr(egg,'name')) #根据后面的参数相当于key输出结果
class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() if hasattr(egg,'func'): #返回bool Foo_func = getattr(egg,'func') #如果存在这个方法或者属性,就返回属性值或者方法的内存地址 #如果不存在,报错,因此要配合hasattr使用 Foo_func() ''' 输出结果: 123 '''
class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() setattr(egg,'sex','属性值') #给类添加一个变量和属性值 print(egg.sex) ''' 输出结果: 属性值 '''
class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() #常用: def show_name(self): print(self.name + ' sb') setattr(egg,'sh_name',show_name) egg.sh_name(egg) show_name(egg) egg.sh_name() ''' 输出结果: egon sb '''
class Foo: def __init__(self): self.name = 'egon' self.age = 73 def func(self): print(123) egg = Foo() delattr delattr(egg,'name') #删除 print(egg.name) #删除了之后会找不到会报错
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')) print(hasattr(obj,'say_hi')) #获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 #设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj)) #删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__)
类也是对象
class Foo: f = 123 #类变量 @classmethod def class_method_demo(cls): print('class_method_demo') @staticmethod def static_method_demo(): print('static_method_demo') # if hasattr(Foo,'f'): # print(getattr(Foo,'f')) print(hasattr(Foo,'class_method_demo')) method = getattr(Foo,'class_method_demo') method() print(hasattr(Foo,'static_method_demo')) method2 = getattr(Foo,'static_method_demo') method2() #类也是对象
在其他模块的反射
#my_module文件内容 def test(): print('test') import my_module print(hasattr(my_module,'test')) #返回一个布尔值 func_test = getattr(my_module,'test') #反射给一个变量 func_test() #然后变量调用执行文件内容 getattr(my_module,'test')() #还可以这种用法 ''' 输出结果: True test test '''
在本模块的反射
def demo1(): print('demo1') import sys print(__name__) #'__main__' print(sys.modules) #'__main__': <module '__main__' from 'D:/Python代码文件存放目录/S6/day26/6反射3.py'> module_obj =sys.modules[__name__] #sys.modules['__main__'] # module_obj : <module '__main__' from 'D:/Python代码文件存放目录/S6/day26/6反射3.py'> print(module_obj) print(hasattr(module_obj,'demo1')) getattr(module_obj,'demo1')() # #在本模块中应用反射
#对象 #类 #模块 : 本模块和导入的模块 def register(): print('register') def login(): pass def show_shoppinglst(): pass # print('注册,登录') ret = input('欢迎,请输入您要做的操作: ') import sys # print(sys.modules) my_module = sys.modules[__name__] if hasattr(my_module,ret): getattr(my_module,ret)()
自定义格式字符串
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) ''' 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'))
__str__和__repr__
class Foo: def __init__(self,name): self.name = name def __str__(self): return '%s obj info in str'%self.name def __repr__(self): return 'obj info in repr' f = Foo('egon') # print(f) print('%s'%f) print('%r'%f) print(repr(f)) # f.__repr__() print(str(f)) ''' 输出结果: egon obj info in str obj info in repr obj info in repr egon obj info in str '''
总结:
#当打印一个对象的时候,如果实现了str,打印中的返回值
#当str没有被实现的时候,就会调用repr方法
#但是当你用字符串格式化的时候 %s和%r会分别去调用__str__和__repr__
#不管是在字符串格式化的时候还是在打印对象的时候,repr方法都可以作为str方法的替补
#但反之不行
#用于友好的表示对象。如果str和repr方法你只能实现一个:先实现repr
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f = Foo() print(123) print(123) print(123) print(123) print(123) #如果没有执行会在程序结束的时候执行 ''' 123 123 123 123 123 执行我啦 ''' class Foo: def __del__(self): print('执行我啦') f = Foo() print(123) print(123) del f #当如果在中间执行了就会直接执行不会再程序结束时候执行 print(123) print(123) print(123) ''' 123 123 执行我啦 123 123 123 '''
class A: def __init__(self): self.x = 1 print('in init function') def __new__(cls, *args, **kwargs): print('in new function') return object.__new__(A, *args, **kwargs) a = A() print(a.x)
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() two.a = 3 print(one.a) # 3 # one和two完全相同,可以用id(), ==, is检测 print(id(one)) # 29097904 print(id(two)) # 29097904 print(one == two) # True print(one is two)
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
__len__
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a))
__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))
__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)