2017年4月25日 python 之__setitem__,__getitem,__delitem__等属性

__setitem__,__getitem,__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)

f=Foo("adamander")
print(f.name)
print(f['name'])
f['age']=18
f['age1']=19

print(f['age'])
print(f.age1)
del f.age1
del f['age']

print(f.__dict__)

__slots__:

#使用类.xxx,或者对象.xxx,来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的字典是独立的)
#字典会占用大量的内存,如果有一个属性很少的类,但是实例很多的类,用__slots__来代替__dict__,限制对象属性数量,对所有对象属性统一管理,
#节省内存.缺点是不能再给实例添加新属性,只能用里面有的。
class People:
    __slots__ = ['x','y','z']

p=People()
p.x=10
p.y=20
p.z=30
print(p.x,p.y,p.z)

利用__iter__和__next__实现迭代器和range():

#实现迭代器协议
from collections import Iterable,Iterator

class Foo:
    def __init__(self,start):
        self.start=start

    def __iter__(self):
        return self

    def __next__(self):
        n=self.start
        self.start+=1
        return n

f=Foo(0)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))


#一直不停的往下加
# for i in f:
#     print(i)
# 实现range()

class Range:
    def __init__(self,start,end):
        self.start=start
        self.end=end

    def __iter__(self):
        return self

    def __next__(self):
        if self.start==self.end:
            raise StopIteration
        n=self.start
        self.start+=1
        return n

for i in Range(3, 8):
    print(i)

 

__doc__:描述文档

class Foo:
    '我是class描述信息'
    pass
print(Foo.__doc__)
#输出:我是class描述信息
#该属性无法继承给子类
def Func():
    '我是def描述信息'
    pass
print(Func.__doc__)
#输出:我是def描述信息

__del__:析构方法

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

import time
class Open:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        self.file=open(filename,mode,encoding=encoding)
    def __enter__(self):
        print("enter=====>")
        return self
    def write(self,line):
        t=time.strftime('%Y-%m-%d %T')
        self.file.write('%s %s' %(t,line))

    def __getattr__(self, item):
        return getattr(self.file,item)
    def __del__(self):
        print("===>del")
        
    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)
        self.file.close()

with Open('b.txt','w+') as f:
    f.write("xxxx")
    f.write("xxxx")
    f.write("xxxx")

__call__:是否可调用

# __call__实例调用,没有他,实例是不可调用的
class People:
    def __init__(self,name):
        self.name=name
    # def __call__(self, *args, **kwargs):
    #     pass


p=People("ada")
print(callable(People))  
#True
print(callable(p))
#False,然而放开注释就是True

__enter__和__exit__:

# with open('a.txt') as f:
#   '代码块'
# 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量,即f')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('当with中代码块执行完毕时执行我')


with Open('a.txt') as f:
    print('=====>执行代码块')
    # print(f,f.name)
    
    
# 运行结果:
# 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量,即f
# =====>执行代码块
# 当with中代码块执行完毕时执行我

 

metaclass 元类:

# typer===>produce class===>produce obj

# type称谓元类,是所有类的类,利用type控制类的行为, 模拟class关键字创建类的过程
class Foo:
    x=1
    def run(self):
        pass

print(type(Foo))


class_name="Bar"
def Run(self):
    print("%s is running"%self.name)

bases=(object,)
class_dic={
    "x":1,
    "run":Run
}


Bar=type(class_name,bases,class_dic)
print(Bar)
print(type(Bar))

print(type("123"))
print(type(123))

# 运行结果:
# <class 'type'>
# <class '__main__.Bar'>
# <class 'type'>
# <class 'str'>
# <class 'int'>
元类是类的类,是类的模板

元类是用来控制如何创建类的,正如类是创建对象的模板一样

元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)

type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

创建类的两种方式:

# 创建类的两种方式
# 方式一:

class Foo:
    def func(self):
        print('from func')
         
# 方式二:
x = 1
def func(self):
    print('from func')
 
Foo=type('Foo',(object,),{'func':func,'x':1})
#利用元类来设计一个类,要求类内的函数必须写注释
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        for key in class_dic:
            if not callable(class_dic[key]):continue
            if not class_dic[key].__doc__:
                raise TypeError("all the func must be notes")


class Foo(metaclass=Mymeta):
    x=1
    def run(self):
        '所有函数必须写注释'
        print("class Foo")

Foo()

终极:盗墓笔记的终极

#元类总结
class Mymeta(type):
    def __init__(self,name,bases,dic):
        print('===>Mymeta.__init__')


    def __new__(cls, *args, **kwargs):
        print('===>Mymeta.__new__')
        return type.__new__(cls,*args,**kwargs)

    def __call__(self, *args, **kwargs):
        print('aaa')
        obj=self.__new__(self)
        self.__init__(self,*args,**kwargs)
        return obj

class Foo(object,metaclass=Mymeta):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)

'''
需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__

而爹.__call__一般做两件事:
1.调用name.__new__方法并返回一个对象
2.进而调用name.__init__方法对儿子name进行初始化
'''

'''
class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
Foo=Mymeta('foo',(...),{...})
因此我们可以看到,只定义class就会有如下执行效果
===>Mymeta.__new__
===>Mymeta.__init__
实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
'''

'''
obj=Foo('egon')
的原理同上
'''

'''
总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
1.谁后面跟括号,就从谁的爹中找__call__方法执行
type->Mymeta->Foo->obj
Mymeta()触发type.__call__
Foo()触发Mymeta.__call__
obj()触发Foo.__call__
2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
'''

 

转载于:https://www.cnblogs.com/adamans/articles/6762560.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值