Python类的内置方法

一、类的type

class A:pass

print(type(A))              # <class 'type'>
print(type(object))         # <class 'type'>
print(type(type))           # <class 'type'>

 

① 所有的对象的type都是创造这个对象类

② 所有没有指定metaclass的类的type都是type

③ 指定了metaclass,这个类的type就是指定的metaclass的值

④ 类也是被创造出来的,type是创造类的机制,即元类是创造类的机制

 

所有的对象的type都是创造这个对象类

class A:pass

a = A()
print(type(a) is A)         # True

 

所有没有指定metaclass的类的type都是type

class A():pass
print(type(A))              # <class 'type'>

 

 指定了metaclass,这个类的type就是指定的metaclass的值

from abc import ABCMeta
class A(metaclass=ABCMeta):pass
print(type(A))                      # <class 'abc.ABCMeta'>

 

类也是被创造出来的,type是创造类的机制,即元类是创造类的机制

print(type(type) is type(object))       # True,type和object的type都是 <class 'type'>
print(isinstance(type,object))          # True,type和object都属于<class 'type'>
print(isinstance(object,type))          # True,type和object都属于<class 'type'>

print(issubclass(type,object))          # True,type是object的子类
print(issubclass(object,type))          # False

 

二、__new__  构造方法

__new__ :构造方法,类实例化对象第一步创建了一个对象空间,这个对象空间是由__new__来创建的,继承object的__new__方法

__init__:初始化方法

类实例化对象的时候,先执行的 __new__,再执行__init__。

 

 

类实例化对象的内存机制:

实例化对象先执行__new__方法,但是类里没有__new__的方法,到父类object中去找到__new__方法并执行,开辟了属于对象的空间,这时才开始执行__init__方法,把self参数传进去才是刚才创造的空间。

 

整个过程把类比作模板,创造对象比作捏泥像,__new__方法是捏出来泥像,__init__是给泥像装饰。

class A:
    def __init__(self):                     # 初始化方法
        print('执行初始化方法')
    def __new__(cls, *args, **kwargs):      # 构造方法
        print('执行构造方法')
        return object.__new__(cls)

a = A()

'''
执行构造方法
执行初始化方法
'''

 

三、单例模式

关于设计模式:

常用有23种设计模式,源于Java,为了规范java的开发。

python一种是推崇设计模式,另一种是贬低设计模式。

 

单例模式:一个类无论实例化多少次,都只有一个对象,只开辟一个空间,这种就是单例模式。

单例模式下,创造的对象的属性是最后一个对象的属性,一直再赋值。

class City:
    __initialize = 0                            # 静态属性
    def __init__(self,city):
        self.city = city

    def __new__(cls, *args, **kwargs):
        if not cls.__initialize:
            cls.__initialize = object.__new__(cls)      # 把对象空间地址赋值静态属性
        return cls.__initialize

gz = City('广州')
sz = City('深圳')
print(gz,sz)
print(gz.city,sz.city)

'''
<__main__.City object at 0x0000022B2DCBC6A0> <__main__.City object at 0x0000022B2DCBC6A0>
深圳 深圳
'''

 

四、__del__ 析构方法

① 析构方法是销毁对象时会调用__del__方法,执行del就会触发__del__的方法

② 在删除这个类创建的对象的时候会先触发这个方法,再删除对象,主要是做清理的工作,需要手动归还资源给操作系统,比如:关闭文件,关闭网络的连接,关闭数据库的连接等。

③ 无论是手动删除对象还是程序结束自动删除对象,本质上都是执行del 对象,只要调用del 对象,就会触发__del__方法

④ 构造方法和析构方法是一对的

class A:
    def __init__(self,name):                # 初始化方法
        self.name = name
        print(self.name)
        print('执行初始化方法1')
    def __new__(cls, *args, **kwargs):      # 构造方法
        print('执行构造方法!')
        return object.__new__(cls)
    def __del__(self):                      # 析构方法
        print('执行析构方法!')


a = A('苹果')
print('-----分割线-----')

'''
执行构造方法!
苹果
执行初始化方法1
-----分割线-----
执行析构方法!
'''

 

总结:初始化对象先执行__new__方法,再执行__init__方法,然后把self传进去,执行__init__的内容,当整个程序执行完自动删除对象,触发了__del__方法,执行__del__方法的内容。

 

五、__len__ 方法

① 所有使用len()的数据类型都有__len__的方法,使用len()的数据类型:str,list,dict,tuple,set

② 只要在类中定义__len__方法,并且方法内return整数,就能使用len(对象)

③ 若要统计对象的长度,定义__len__的方法比较好

class Fruits:
    def __init__(self,name):
        self.name = name
        self.fruit_lis = []

    def __len__(self):
        return len(self.fruit_lis)

durian = Fruits('榴莲')
durian.fruit_lis.append('苹果')
durian.fruit_lis.append('番茄')
durian.fruit_lis.append('西瓜')
durian.fruit_lis.append('雪梨')
durian.fruit_lis.append('香蕉')
ret = len(durian)
print(ret)                               # 5

 

六、__eq__ 方法

① __eq__方法判断对象是否相等,但是object类的__eq__方法是通过对象的内存地址判断是否相等

② __eq__方法 有时会配合__hash__方法使用,判断对象里的对象属性是否相等

③ obj.__eq__(obj2) 相当于 obj == obj2

class City:
    def __init__(self,city):
        self.city = city


    def __eq__(self, other):
        return self.__dict__ == other.__dict__

c1 = City('广州')
c2 = City('广州')
print(c1.__eq__(c2))          # 调用类的__eq__方法
print(c1 == c2)               # 调用类的__eq__方法
print(c1,c2)                  # 对象空间的地址

'''
True
True
<__main__.C

 

七、__hash__ 方法

默认的__hash__()继承自对象本身,返回一个基于对象的内部ID值。

相同的hash值:这意味着两个对象可能是相等的。该hash值为我们提供了一个快速检查对象相等的可能性。如果hash值是不同的,两个对象不可能是相等的,他们也不可能是相同的对象。至关重要的是,内部ID和默认__hash__()方法间有一种强联系。

等号比较:这意味着hash值也一定相等。这是==操作符的定义。对象可能是相同的对象。

相同的IDD:这意味着他们是同一个对象。进行了等号比较且有相同的hash值。这是is操作符的定义。

然而,反过来是不正确的。对象可以有相同的hash值但比较是不相等的。在创建集合或字典时导致一些预计的处理开销是正当的。我们不能确切的从更大的数据结构创建不同的64位hash值。将有不相等的对象被简化为一致相等的hash值。

 

特点:

① 每次执行的哈希值都会变化

② 在一次执行哈希的过程中,对同一个值的hash结果总是不变的

 

字典寻址快的原因是运用了哈希算法,比二分查找快。

字典在内存中的存储方式:

  每存储在内存的数据都有一个内存地址,字典会对键key进行哈希hash(key),把值放在hash的对应地址,所以字典的键是可哈希的

 

hash算法的特点:

① 对于相同的值在一次程序的运行中是不会变化的

② 对于不同的值在一次程序的运行中总是不同的

 

set的去重机制:

① 对每一个元素进行hash,计算出一个内存地址

② 到这个内存地址上查看,如果这块内存中没有值,将这个元素存到对应的内存地址上

③ 到这个内存地址上查看,如果这块内存中有值,判断这两个值是否相等。如果相等就舍弃后面的值,如果不相等就二次寻址,再找一个新的空间来存储这个值

 

自定义__hash__和__eq__方法

 

class Fruits:
    def __init__(self,name):
        self.name = name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

fruits_lis = ['apple','orange','banana']
obj_lis = []
for i in range(9):
    name = Fruits(fruits_lis[i%3])
    obj_lis.append(name)
print(obj_lis)
print('-'*100)
ret = set(obj_lis)
print(ret)

'''
[<__main__.Fruits object at 0x000001A5EF92C6D8>, <__main__.Fruits object at 0x000001A5EF9373C8>, <__main__.Fruits object at 0x000001A5EF9370F0>, <__main__.Fruits object at 0x000001A5EF937400>, <__main__.Fruits object at 0x000001A5EF937470>, <__main__.Fruits object at 0x000001A5EF937518>, <__main__.Fruits object at 0x000001A5EF937550>, <__main__.Fruits object at 0x000001A5EF937588>, <__main__.Fruits object at 0x000001A5EF9375C0>]
----------------------------------------------------------------------------------------------------
{<__main__.Fruits object at 0x000001A5EF9370F0>, <__main__.Fruits object at 0x000001A5EF92C6D8>, <__main__.Fruits object at 0x000001A5EF9373C8>}

'''

 

posted @ 2018-09-03 21:47  st--st  阅读(641)  评论(0编辑  收藏  举报