爱根,充盈,满满的。。。进击的巨根,面向对象,隐退之作。。。

setattr,hasattr,getattr,delattr#####__setattr__,__getattr__,__delattr__#####__setitem__,__getitem__,__delitem__用法与区别汇总!!!
class People:
    x=1
    def __init__(self,name,age):
        print(1)
        self.name=name
        self.age=age
        print(2)
    def __setattr__(self, key, value):
        print(3)
        self.__dict__[key]=value
    def __setitem__(self, key, value):
        print(4)
        self.__dict__[key]=value
    def __getattr__(self, item):
        print(5)
        return True                 #这是处理异常的过程。
    def __getitem__(self, item):
        print(6)
        return self.__dict__[item]
    def __delattr__(self, item):
        print(7)
        self.__dict__.pop(item)
    def __delitem__(self, key):
        print(8)
        self.__dict__.pop(key)
p=People("egon",18)      #执行过程为1332,就是再函数的实例化阶段,就会触发__setattr__的运行。
print(p.name)            #直接可以查看属性,这个没问题。
p.sex="handsome"         #会触发3__setattr__的运行,这是再修改阶段。
p["sex"]="handsome"      #会触发4__setitem__的运行,注意[]中必须是字符串。
p.sexx                   #会触发5__getattr__的运行,因为没有这个属性,所以会触发。
p.sex                    #不会触发__getattr__的运行。
p["age"]                 #会触发6__getitem__的运行,注意[]中必须是字符串。
# p["sexx"]              #报错。
# del p.sex              #会触发7__delattr__的运行。
del p["sex"]             #会触发8__delitem__的运行,注意[]中必须是字符串。
################总结:attr系列是通过.的方式来调用,而item系列是通过类似操作字典的方式来进行调用。#################################
print(hasattr(People,"__init__"))      #True
print(getattr(People,"x"))             #1
getattr(People,"__getattr__")(p,1)     #5
# delattr(People,"__getattr__")          #删除该函数属性。
# getattr(People,"__getattr__")(p,1)     #再次调用则报错。
setattr(People,"x",999)                  #修改类的数据属性。
print(People.x)                          #999,修改成功。
                      __slots__
'''
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
  当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
  字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
  实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性了,比如多继承。大多数情况下
  ,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__,比如在程序中需要创建某个类的几百万个实例对象 。关于__slots__的一个常见误区
  是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存
  优化工具。
'''
class People:
    __slots__ = ["x","y","z"]      #所有的类产生的对象,只有这三个属性。

p=People()
p.x=1
p.y=2
p.z=3
print(p.__dict__)   # 'People' object has no attribute '__dict__'
# p.v=4             #不能再新增属性了,限制了就是三个。
People.a=7
print(People.a)
                              __call__

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

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()。

class People:
    def __init__(self,name):
        self.name=name
    def __call__(self, *args, **kwargs):
        print('I',*args, **kwargs)
p=People('egon')
print(callable(People))     #True
print(callable(p))          #True
p("love egon")              #I love egon
print(p.__dict__)           #{'name': 'egon'}
print("__call__" in People.__dict__)      #True
                    __iter__                __next__
from
collections import Iterator,Iterable class Range: def __init__(self,s,e): self.s=s self.e=e def __iter__(self): return self.next(self) def __next__(self): if self.s>=self.e: raise StopIteration n=self.s self.s+=1 return n r=Range(0,10) print(isinstance(r,Iterable)) #True print(isinstance(r,Iterator)) #True,如果没有__next__函数的话,这里会是False。 for i in Range(1,11): print(i)
                              实现上下文管理协议

用途或者说好处:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预。

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处。

import time
class Open:
    def __init__(self,file_name,mode="r",encoding="utf8"):
        print(1)
        self.file_name=file_name
        self.mode=mode
        self.encoding=encoding
        self.bar=open(file_name,mode=mode,encoding=encoding)
    def write(self,value):
        Time=time.strftime("%Y--%m--%d  %T")
        self.bar.write("%s%s
"%(Time,value))
        self.bar.flush()
    def __getattr__(self, item):
        return getattr(self.bar,item)
    def __enter__(self):
        print(2)
        return self             #这里必须返回self,不然调到的write函数只是句柄的write,与自定义的方法无关。
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        print(3)
        self.bar.close()
        return True
#Open("a.txt","a+")              #定义阶段必然执行自己的__init__函数。
with Open("a.txt","a+") as f:       #这一步先打印1,然后将进入__enter__函数中,打印2,将对象自己返回,并赋值给f。
    f.write("---------------------------
")    #通过自定义的write方法写入文件。
    # raise TypeError("出错了!!!")           #报错会进入__exit__并打印错误,并关闭文件。
    print("你好啊!!!")           #正常结束会触发__exit__并关闭文件。如果先报错的话,就关闭文件了,下面的“你好啊”也不会打印。
print("你真帅!!!")               #就算会报错,这一步也会执行的。       
                            描述信息__doc__
class
Foo: pass print(Foo.__doc__) #None class Foo: "我定义了描述信息" pass class Bar(Foo): pass print(Foo.__doc__) #我定义了描述信息 print(Bar.__doc__) #None 说明描述信息无法继承。
                                   析构函数
#
析构方法,当对象在内存中被释放时,自动触发执行。 # 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构 # 函数的调用是由解释器在进行垃圾回收时自动触发执行的。 import time class Open: def __init__(self,file_path,mode='r',encode='utf-8'): self.f=open(file_path,mode=mode,encoding=encode) def __del__(self): self.f.close() print("来自del") # f=Open("a.txt") #拿到文件句柄f。 # del f #删除对f的引用。立即显示"来自del",因为用完了,自动触发__del__析构函数运行。 # time.sleep(3) #睡3秒, # print("3秒过后") #打印内容。 f=Open("a.txt") #拿到文件句柄f。 f1=f del f #因为f1还在引用,所以不会触发内存回收机制。 time.sleep(3) #睡3秒, print("3秒过后") #打印内容。之后再回收。
                            瞎鸡巴搞些实验,记不住,嗯嗯嗯
#
元类是类的类,是类的模板。 # 元类是用来控制如何创建类的,正如类是创建对象的模板一样。 # 元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)。 # type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象。 # class Foo: # pass # f=Foo() # print(type(f)) #<class '__main__.Foo'> # print(type(Foo)) #<class 'type'> #自己通过元类来创建类。 # x = 1 # def run(): # print("1111111111111") # class_name="caonima" # class_bases=(object,) # class_dic={"x":1,"run":run} # a=type(class_name,class_bases,class_dic) #type(类名,类的继承关系,类的属性字典)。 # print(type(a)) #<class 'type'> 是type类的一个实例。 # print(a.__dict__) #{'x': 1, 'run': <function run at 0x0000000001E8F730>, '__module__': '__main__', '__dict__': # # <attribute '__dict__' of 'caonima' objects>, '__weakref__': <attribute '__weakref__' of 'caonima' objects>, # # '__doc__': None} # print(a) #<class '__main__.caonima'> 是”草泥马“类,也就是type生成的一个类对象。 class Meta(type): #将自己伪装成一个元类。 def __init__(self,class_name,class_bases,class_dict): #元类的__init__方法其实在定义Foo类对象的时候会用,找不到的话 print(class_name,class_bases,class_dict) #去type里面找,因为继承了type的所有属性。 for key in class_dict: #遍历字典中所有的key。 if not callable(class_dict[key]):continue #如果值不是可被调用的(函数都是可被调用的),继续找,找到的话进入下一步。 if not class_dict[key].__doc__: #拿到value,内存地址,看看是否有注释信息。 raise TypeError("没有写注释,需要加入!") #只要有一个函数没有注释信息的话,就会报错。 # print(class_dict.__doc__) #看不懂出来的内容,草。 def __call__(self, *args, **kwargs): #__call__方法其实是供类Foo对象来调用的,实例过程中使用。 obj=self.__new__(self) #定义一个空的对象,这里的self其实就是类Foo对象。 self.__init__(obj,*args,**kwargs) #这个类Foo对象调用自己的__init__方法,将obj.name="egon"定义。 return obj #返回这个被增加了属性的对象。其实就是f。 class Foo(metaclass=Meta): #Foo () {'__module__': '__main__', '__qualname__': 'Foo', 'x': 1, '__init__':<function Foo.__init__ at 0x00000000027CF840>, # 'run': <function Foo.run at 0x00000000027CF8C8>} x=1 def __init__(self,name): "已写入注释。" self.name=name def run(self): "已写入注释。" print("%s is running"%self.name) print(Foo,Foo.x) #<class '__main__.Foo'> 1 定义阶段。 f=Foo("egon") #实例化阶段。 print(f.name) #egon #自我定制的时候,少了好多属性,,, # x=1 # def __init__(self,name): # self.name=name # def run(self): # print("%s is running"%self.name) # Foo=Meta("Foo",(Meta,),{"x":1,"__init__":__init__,"run":run}) # #Foo (<class '__main__.Meta'>,) {'x': 1, '__init__': <function __init__ at 0x00000000005B3E18>, 'run': <function run at 0x00000000027FF7B8>} # print(Foo,Foo.x) #<class '__main__.Foo'> 1
原文地址:https://www.cnblogs.com/chedanlangren/p/6764200.html