面向对象之内置方法

#python 内置方法      为类内建的函数

#isinstance 检查obj 是否是类cls 的对象
class Foo:
pass
obj = Foo()
print(isinstance(obj,Foo))


#issubclass 检查sub类 是否是father 类的父类
class Foo():
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo))


#反射 (自省) :程序可以访问,检测和修改它本身状态或行为的一种能力
#python 中的反射 : 通过字符串的形式操作对象相关的属性 适用于类和对象

import sys

class People:
country = 'china'
def __init__(self,name):
self.name = name
def walk(self):
print('%s is walking '%self.name)
p = People('egon')

#hasattr #检测对象或类是否有这个属性
print(hasattr(People,'country'))
print(hasattr(People,'walk'))

p.sex = 'male'
print(hasattr(p,'sex')) #p.sex
print(hasattr(p,'walk')) #p.walk

#getattr #得到对象或类的某个属性
res = getattr(People,'country')
print(res)
f = getattr(p,'walk')
print(f)
f1 = getattr(People,'walk')
print(f1)
#setattr #为对象和类设置新的属性
setattr(p,'age',18)
print(getattr(p,'age'))
print(getattr(p,'xxxxx','not found attribute'))

if hasattr(p,'age'):
print(getattr(p,'age'))
#delattr #删除对象或类的属性
delattr(p,'age')
print(hasattr(p,'age'))

#.py文件的两种用法:
#脚本文件 :可以直接执行当前这个文件,那这个文件就是脚本文件
#当做模块在另一个程序中调用

#反射当前模块的成员
this_module = sys.modules[__name__]
print(this_module) #拿到这个模块的绝对路径

print(hasattr(this_module,'p'))
print(getattr(this_module,'p')) #print(this_module.p) 得到当前模块下的一个对象
print(__name__)


#反射的用途
# 1字符串反射成为一个命令 远程控制
import sys
def add():
print('add')

def change():
print('change')

def search():
print('search')


def delete():
print('delete')

func_dic={
'add':add,
'change':change,
'search':search,
'delete':delete
}
while True:
cmd = input('>> :')
if not cmd:continue
if cmd in func_dic: # hasattr
func = func_dic[cmd] #getattr
func()

this_module = sys.modules[__name__]
while True:
cmd = input('>> :')
if not cmd:continue
if hasattr(this_module,cmd):
func =getattr(this_module,cmd)
func()


#2可插拔机制:ftpserver ftpclient
#反射的好处就是,可以事先定义好接口,接口只有在被完成之后才会真正执行,这实现了即插即用
#即你可以事先把主要的逻辑写好(只定义接口),然后后期再实现接口

#3以字符串的形式导入模块 动态导入模块
#利用内置函数 不推荐
m = input('module :')
m1 = __import__(m)
print(m1.time())
# 官方推荐
import importlib
t = importlib.import_module(m)
print(t.time())

# __setattr__ __delattr__ __getattr__
#与property的应用场景的区别:
#property可以自定义对象对于所属类的一个属性的访问和操作
#下述三者可以自定义类的所有属性被操作的权限
#都可以应用到 定制自己想要的数据类型
class Foo:
def __init__(self,name):
self.name = name
def __setattr__(self,key,value): #添加或修改属性会触发它的执行 可以限制所有属性设置时的条件
print('---------setter------key:%s,value:%s'%(key,value))

self.__dict__[key]=value
def __delattr__(self,item): #删除属性可以触发它的执行 可以限制所有属性在什么条件下才能删除
print('--delattr-----%s'%item)
print(self.__dict__.pop(item))
def __getattr__(self,item): #属性不存在的情况下才会触发
print('---------getsttr----%s'%item)


f =Foo('egon')
f.age = 18
f.sex = 'male'
print(f.__dict__)

del f.age
print(f.__dict__)

print(f.xxxxxxx)

#定制自己的数据类型 (二次加工标准类型) (包装)
#1基于继承实现
class List(list):
def append(self,p_obj):
if not isinstance(p_obj,int):
raise TypeError('must be int')
super().append(p_obj)
def insert(self, index:int, p_object:int):
#print(insert.__annotations__)
if not isinstance(p_object,int):
raise TypeError('must be int')
super().insert(index,p_object)

l = List([1,2])
l.append(3)
print(l)


l.insert(0,8)
print(l)
l.insert(2,9)
print(l)


#不能用继承,来实现open函数的功能
f = open('a.txt','w')
print(f)
f.write('1111111111')
#2授权的方式实现定制自己的数据类型
#授权是包装的一个特性,包装一个类型,通常是对已存在的类型的一些定制,这种方法可以新建,修改或删除原有产品的功能
#其他则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性
import time
class Open:
def __init__(self,file_path,m = 'r',encode = 'utf8'):
self.file_path = file_path
self.mode = m
self.encoding = encode
self.x = open(file_path,mode = m,encoding = encode)
def write(self,line):
# print('f自己的write',line)
t = time.strftime('%y-%m-%d %X')
self.x.write('%s %s'%(t,line))

def __getattr__(self,item):
return getattr(self.x,item)


f = Open('a.txt','r')
# print(f)
f.write('1111111111111\n')
f.write('1111111111111\n')
f.write('1111111111111\n')
f.write('1111111111111\n')
f.write('1111111111111\n')
f.write('1111111111111\n')

f.seek(0)
print(f.read())
# 基于授权定制自己的列表类型,要求定制的自己的__init__方法,
# 定制自己的append:只能向列表加入字符串类型的值
# 定制显示列表中间那个值的属性(提示:property)
# 其余方法都使用list默认的(提示:__getattr__加反射)


class List:
def __init__(self,*args):
self.x =list(args)
def append(self,value):
if not isinstance(value,str):
raise TypeError('must be str')
self.x.append(value)
@property
def mid(self):
return self.x[int(len(self.x)/2)]
def __getattr__(self,item):
return getattr(self.x,item)
def __str__(self):
return str(self.x)




l = List(1,2,3,4,5,6)
print(l)

l.append('123')
l.append('123')
l.append('123')
l.append('123')
print(l)
print(l.mid)

l.insert(0,'9')
print(l)




#__getitem__ __setitem__ __delitem__
# 把对象操作属性模拟成字典的格式
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
self.__dict__.pop(key)

f = Foo('egon')
print(f['name'])
f['age']= 18
print(f.__dict__)
del f['age']
print(f.__dict__)
#__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)


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'))

#__slots__
# 它所产生的对象只能设置__slots__里面的属性,并且对象没有命名空间
# 大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
# 关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。
# 尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。 更多的是用来作为一个内存优化工具

class People:
__slots__=['x','y','z']

p=People()
print(People.__dict__)

p.x = 1
p.y =2
p.z = 3
print(p.x,p.y,p.z)
# print(p.__dict__)
# p.d= 9
# print(p.d)

#__iter__ __next__
# #实现迭代器协议
from collections import Iterable,Iterator
class Foo:
def __init__(self,start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start > 10:
raise StopIteration
n = self.start
self.start += 1
return n

f = Foo(0)
for i in f:
print(i)


# 实现range
class Bar:
def __init__(self,start,end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start > (self.end-1):
raise StopIteration
n = self.start
self.start += 1
return n

b = Bar(1,6)
for i in b:
print(i)

#__doc__ __module__ __class__
class Foo:
'Foo class'
def __init__(self):
pass
f = Foo()
print(f.__doc__)
print(f.__module__)
print(f.__class__)
#__del__ 析构方法 当对象在内存中被释放时,自动触发执行

class Open:
def __init__(self,filepath,mode = 'r',encode = 'utf8'):
self.f = open(filepath,mode = mode ,encoding = encode)
def write(self):
pass
def __getattr__(self, item):
return getattr(self.f,item)
def __del__(self): #此方法一般无须定义,python会在对象被释放时,内存定时回收垃圾
print('----------->del')
self.f.close()

f = Open('a.txt','r')

print('ttttttttttt')
f1 = f
del f #会立即触发类的__del__ 函数


# f.read()
print('ggggggggg')


#__call__ 对象后面加括号,触发执行

class Foo:
def __init__(self):
pass
def __call__(self,*args,**kwargs):
print('call')
f = Foo()
f()


#metaclass
# type称为元类,是所有类的类,利用type模拟class关键字的创建类的过程
def run(self):
print('%s is running '%self)
class_name = 'Bar'
bases = (object,)
class_dict ={
'x':1,
'run':run
}
Bar = type(class_name,bases,class_dict)
print(Bar)
print(type(Bar))

s = type('spam',(),{})
print(s)




# 自定义元类
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dict):
for key in class_dict:
if not callable(class_dict[key]):continue
if not class_dict[key].__doc__:
# raise TypeError('没有注释啊')
pass

class Foo(metaclass=Mymeta): #type.__init__(self,class_name,class_bases,class_dict)
x = 1
def run(self):
'run function'
print('runing')

Foo = Mymeta('Foo',(object,),{'x':1,'run':run})
print(Foo.__dict__)

# 类实例化对象时的init自动触发机制
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dict):
pass
def __call__(self, *args, **kwargs): #对象后面加括号,触发执行
obj = self.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj
class Foo(metaclass=Mymeta):
x = 1
def __init__(self,name):
self.name = name
def run(self):
print('running')
print(Foo)
f = Foo('egon')
print(f)



#__enter__ __exit__
# 上下文管理协议
with open('a.txt') as f:
'fffffffffff'


class Foo:
def __enter__(self):
print('=====================>enter')
return 1111111111
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit')
print('exc_type',exc_type)
print('exc_val',exc_val)
print('exc_tb',exc_tb)
return True
with Foo(): #res = Foo().__enter__()
pass




with Foo() as obj: #obj = res
print('with foo 的子代码块',obj)
raise NameError('名字没有定义')
print('yyyyyyyyyyy')


#实现上下文管理协议
import time
class Open:
def __init__(self,file_path,m = 'r',encode = 'utf8'):
self.file_path = file_path
self.mode = m
self.encoding = encode
self.x = open(file_path,mode = m,encoding = encode)
def write(self,line):
# print('f自己的write',line)
t = time.strftime('%y-%m-%d %X')
self.x.write('%s %s'%(t,line))

def __getattr__(self,item):
return getattr(self.x,item)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
return True


with Open('a.txt','w') as file:
file.write('dddddddddddddd\n')
file.write('dddddddddddddd\n')
file.write('dddddddddddddd\n')
print('ggggggg')
file.write('dddddddddddddd\n')
 #__eq__ 和__hash__
继承obj的类自带哈希属性,将类所有的属性值(字符串)摘要成为哈希值
自己定义的类没有哈希属性
假设有100个person的对象,
若两个对象的obj1,obj2的name和sex属性相同
即obj1.name==obj2.name and obj1.sex==obj2.sex
我们认为两个对象为同一个对象,已知一个列表中的100个对象,对这100个对象进行去重。
class Person:
def __init__(self,name,age,sex,weight):
self.name = name
self.age = age
self.sex = sex
self.weight = weight
def __eq__(self, other):
if self.name == other.name and self.sex == other.sex:
return True
def __hash__(self): #自定义哈希方法
return (self.name,self.sex).__hash__()
def __str__(self):
return str(self.__hash__())

a1 = Person('alex',18,'male',60)
a2 = Person('alex',18,'male',60)
print(set([a1,a2])) #会自动触发类中的eq属性和hash属性,比较两者的属性值
print(a1,a2) #打印两个对象的哈希值
 


posted @ 2017-05-01 16:04  柳姑娘  阅读(245)  评论(0编辑  收藏  举报