对象的另一面

当getattr与__getattribute__同时出现时:先找__getattribute__,如果抛出异常则执行getattribute

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4     def __getattr__(self, item):
 5         print("执行的是我")
 6     def __getattribute__(self, item):
 7         print("我是ibute")
 8         raise AttributeError("哈哈")
 9 
10 f1=Foo(10)
11 f1.x
__getattribute__(self, item)

 __str__,__repr__,__format__

class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __repr__(self):
        return "这个是repr"
    def __str__(self):
        return "这个是str"
f1=Foo("szw",18)
print(f1)
# str函数或者print函数--->obj.__str__()
# repr或者交互式解释器--->obj.__repr__()
# 如果__str__没有被定义,那么就会使用__repr__来代替输出
# 注意:这俩方法的返回值必须是字符串,否则抛出异常
format_dic={"ymd":"{0.year}{0.mon}{0.day}",
            "m-d-y":"{0.year}-{0.mon}-{0.day}",
            "y:m:d":"{0.year}:{0.mon}:{0.day}",}
class Data:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day
    def __format__(self, format_spec):
        print("我执行了")
        print("---------->,format_spec")
        if not format_spec or format_spec not in format_dic:
                #如果没传格 式 或传进来的格式找不到 则默认使用“ymd”作为格式
            format_spec="ymd"
        fm=format_dic[format_spec]
        return fm.format(self)
d1=Data(2016,12,26)
# print(format(d1))
# print(format(d1,"ymd"))
print(format(d1,"m-d-y"))
# print(format(d1,"y:m:d"))
# print(format(d1,"lshgia"))

__slots__

'''
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该
只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。           更多的是用来作为一个内存优化工具。

'''
class Foo:
    __slots__="x"
f1=Foo()
f1.x=1
# f1.y=2#报错
print(f1.x)

class Bar:
    __slots__=["x","y"]
n=Bar()
n.x,n.y=1,2
print(n.x,n.y)
移出了__dict__的方法

 __doc__

#该属性无法被继承
class Foo:
    "654131651"
    pass

print(Foo.__doc__)
class Bar(Foo):
    pass
print(Bar.__doc__)#该属性无法继承给子类
查看描述信息

 __module__和__class__

  __module__ 表示当前操作的对象在那个模块

  __class__     表示当前操作的对象的类是什么

from obj.s import Foo
f1=Foo("szw")
print(f1.name)
print(f1.__module__)#查看在那个模块
print(f1.__class__)#查看在那个类
View Code

__del__

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

__del__:析构方法
垃圾回收时触发
class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
del f1
print('------->')

#输出结果
执行我啦
------->

简单示范
简单示范
class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
# del f1
print('------->')

#输出结果
------->
执行我啦





#为何啊???

挖坑埋了你
挖坑埋了你

 __call__

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

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

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 执行 __init__
obj()       # 执行 __call__
View Code

 __next__和__iter__实现迭代器协议

class Foo:
    def __init__(self,n):
        self.n=n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n==100:
            raise StopIteration("终止了")
        self.n+=1
        return self.n
f1=Foo(10)
print(f1.__next__())
print(f1.__next__())
print(f1.__next__())
# for i in f1:
#     print(i)
简单实现
class Fib:
    def __init__(self):
        self._a=0
        self._b=1

    def __iter__(self):
        return self

    def __next__(self):
        self._a,self._b=self._b,self._a + self._b
        return self._a

f1=Fib()

print(f1.__next__())
print(next(f1))
print(next(f1))

for i in f1:
    if i > 100:
        break
    print('%s ' %i,end='')
斐波那契数列

__enter__和__exit__

1 with open('a.txt') as f:
2   '代码块'

 

'''
with触发__enter__
with代码块结束后执行__exit__
'''

class Open:
    def __init__(self,name):
        self.name=name
    def __enter__(self):
        print("with触发enter")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exit")
        # return self
with Open("a.txt")as f: 
    print("--------------")
    print(f.name)
print("000000000000")
View Code

__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行

class Open:
    def __init__(self,name):
        self.name=name
    def __enter__(self):
        print("with触发enter")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        #如果return返回的是True这异常被吞掉
        print("exit")
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True
with Open("a.txt.txt")as f:
    print("--------------")
    print(lsfhoisgsofsaipghsoigh)
    print(f.name)
print("000000000000")
View Code

如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

单例模式:

class LoggerHelper(object):
    _i=None
    
    @classmethod
    def instance(cls):
        if cls._i:
            return cls._i
        else:
            cls._i=LoggerHelper()
            return cls._i

obj1=LoggweHelper.instance()
print(obj1)
obj2=LoggweHelper.instance()
print(obj2)
obj3=LoggweHelper.instance()
print(obj3)
原文地址:https://www.cnblogs.com/shizhengwen/p/6233128.html