运算符重写
#encoding=utf-8
class Vector(object):
    def __init__(self,a,b):
        self.a = a
        self.b = b

    def __str__(self):
        return "Vector(%d,%d)" %(self.a,self.b)

    def __add__(self,other):
        return Vector(self.a + other.a,self.b + other.b)

x = Vector(3,7)
y = Vector(1,-10)
print(x + y)
print(str(x))



类的特殊成员
1.__doc__
类的描述信息
#encoding=utf-8
class Vector(object):
    """类的描述信息"""
    def __init__(self):
        pass
v = Vector()
print(v.__doc__)

2. __module__ 和 __class__
➢ __module__ 表示当前操作的对象在那个模块
➢ __class__  表示当前操作的对象的类是什么
3.__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

>>> class P():
...     def __del__(self):
...         print("del exe")
...
>>> p = P()
>>> del p
del exe


4. __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于
__call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
#encoding=utf-8
class Foo(object):
    
    def __init__(self):
        pass

    def __call__(self,*args,**kwargs):
        print("__call__")

obj = Foo()
obj()#会调用实例的__call__方法




5. __dict__
类或对象中的所有成员



6. __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。


>>> class Foo(object):
...     def __str__(self):
...         return "__str__被调用"
...
>>> obj = Foo()
>>> print(obj)
__str__被调用


7. __getitem__ 、__setitem__ 、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
#encoding=utf-8
class Foo(object):
    
    def __getitem__(self,key):
        print("__getitem__",key)


    def __setitem__(self,key,value):
        print("__setitem__",key,value)

    def __delitem__(self,key):
        print("__delitem__",key)


obj = Foo()
result = obj["k1"]#自动调用 __getitem__
obj['k2'] = 'kkkk'#自动调用 __setitem__
del obj["k1"]#自动调用 __delitem__


8. __getslice__、__setslice__、__delslice__ 在python 2.7可以使用,在3.x已经被去掉了,需要使用__getitem__、__setitem__、__delitem__和__getslice__来实现
#encoding=utf-8
class Foo(object):
    
    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.li = [1,2,3,4,5,6,7]

    def __getitem__(self,item):
        if isinstance(item,slice):
            return self.li[item]
        elif isinstance(item,int):
            return self.li[item]


    def __setitem__(self,key,value):
        print(key,value)
        self.li[key] =value


    def __delitem__(self,key):
        print(key)
        del self.li[key]

a = Foo("alex",18)
print(a[3:5])#自动调用__getitem__
a[0] = 100#自动调用__setitem__
print(a[0])#自动调用__getitem__
del a[0]#自动调用__delitem__
print(a[0])#自动调用__getitem__



9.__iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内
部定义了 __iter__

#encoding=utf-8
class Foo(object):
    
    def __init__(self,sq):
        self.sq = sq

    def __iter__(self):
        return iter(self.sq)


obj = Foo([1,2,3,4,5])
for i in obj:
    print(i)
      





10.__slot__
限制实例可以使用的属性名称
#encoding=utf-8
class Student(object):
    
    __slots__ =("name","age")# 用tuple定义允许绑定的属性名称

s = Student()
s.name = "hhh"
s.age = 25
s.score = 99





11. __new__
 __new__() 方法是在类准备将自身实例化时调用。
 __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。




#encoding=utf-8
class A(object):
    def __init__(self):
        print("init")

    def __new__(cls,*args,**kwargs):
        print("new %s" %cls)
        return object.__new__(cls,*args,**kwargs)

A()

结果分析:
首先调用__new__()方法实例化类,产生类的实例对象;
然后实例对象调用__init__()方法;



继承自object的新式类才有__new__。
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供。
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例。
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。若__new__没有正确返回 当前类 cls的实例,那__init__是不会被调用的,即使是父类的实例也不行。




__new__ 、 __init__区别
__new__()  类实例化时候调用,产生类的实例
__init__() 类实例对象产生后调用,用来初始化对象的数据


单例
#encoding=utf-8
class Singleton(object):
    def __new__(cls,*args,**kwargs):
        if not hasattr(cls,"_instance"):
            orig = super(Singleton,cls)
            cls._instance = orig.__new__(cls,*args,**kwargs)
        return cls._instance

class MyClass(Singleton):
    a = 1
    
one = MyClass()
two = MyClass()#one 和 two 完全相同

two.a = 3
print(one.a)

print(id(one))
print(id(two))
print(one == two)
print(one is two)



python对象销毁(垃圾回收)
同Java语言一样,Python使用了引用计数这一简单技术来追踪内存中的对象。在Python内部记录着所有使用中的对象各有多少引用。一个内部跟踪变量,称为一个引用计数器。当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说,这个对象的引用计数变为0 时,它被垃圾回收。但是回收不是"立即"的,由解释器在适当的时机,将垃圾对象占用的内存空间回收

>>> import sys
>>> print(sys.getrefcount(8787))
3
>>> a = 8787
>>> print(sys.getrefcount(a))
2
>>> b = a
>>> print(sys.getrefcount(a))
3
>>> c = a
>>> print(sys.getrefcount(a))
4
>>> d = c
>>> print(sys.getrefcount(a))
5
>>> [1,2].append(a)
>>> print(sys.getrefcount(a))
5
>>> del d
>>> print(sys.getrefcount(a))
4
>>> del b
>>> print(sys.getrefcount(a))
3
>>> del a
>>> print(sys.getrefcount(a))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

垃圾回收
垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充,垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。在这种情况下,解释器会暂停下来,试图清理所有未引用的循环。析构函数 __del__ ,__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行:

#encoding=utf-8
class Point(object):
    def __init__(self,x=0,y=0):
        self.x = x
        self.y = y
    
    def __del__(self):
        class_name = self.__class__.__name__
        print(class_name,"销毁")


pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1),id(pt2),id(pt3))

del pt1

print(pt2)
print(pt3)
del pt2


print(pt3)
del pt3


print(pt3)


循环引用的对象被销毁
#encoding=utf-8
class LeakTest(object):
   def __init__(self):
       self.a = None
       self.b = None
       print("object = %d born here" %id(self))

A = LeakTest()
B = LeakTest()
A.a = B
B.b = A

import sys
print(sys.getrefcount(A))
print(sys.getrefcount(B))

del A
try:
    print(sys.getrefcount(A))
except Exception as e:
    print(e)

del B

try:
    print(sys.getrefcount(B))
except Exception as e:
    print(e)