一、__getattribute__

object.__getattribute__(self, name)

无条件被调用,通过实例访问属性。如果class中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或引发AttributeError异常)

  
  class Foo:

def __init__(self,x):
self.x = x

def __getattr__(self, item):
print("执行__getattr__")

def __getattribute__(self, item):
print("执行__getattribute__")
# raise AttributeError("不存在的异常")

f = Foo("nick")
print(f.x)
print(f.xxxx)#这里本来调用后应该在__getattribute__中产生AttributeError,然后调用__getattr__,但在#这里__getattribute__被重写了,没有产生AttributeError,所以就没调用__getattr__

  

输出结果

  执行__getattribute__
None
执行__getattribute__
None

  

object.__getattr__(self, name)

当一般位置找不到attribute的时候,会调用getattr,返回一个值或AttributeError异常。

  
  class Foo:

def __init__(self,x):
self.x = x

def __getattr__(self, item):
print("执行__getattr__")

# def __getattribute__(self, item):
# print("执行__getattribute__")
# raise AttributeError("不存在的异常")

f = Foo("nick")
print(f.x)
print(f.xxxx) #这里是执行了新定义的__getattr__方法,并没有直接报错

  

输出结果

  
  nick
执行__getattr__
None

  

每次通过实例访问属性,都会经过__getattribute__函数。

而当属性不存在时,仍然需要访问__getattribute__,不过接着要访问__getattr__。这就好像是一个异常处理函数。 需要注意的是,当使用类访问不存在的变量是,不会经过__getattr__函数。

当属性存在时,经过__getattribute__函数,返回属性的值。

二、__setitem__,__getitem,__delitem__

在类中,对象以object["key"]形式访问属性或方法时调用item系列内置方法,对象以object.属性(以点的形式)调用属性或方法时调用attr系列内置方法。

  
  class Foo:

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

def __getitem__(self, item):
print("执行__getitem__")
return self.__dict__[item]

def __setitem__(self, key, value):
print("执行__setitem__")
self.__dict__[key] = value

def __delitem__(self, key):
print("执行__delitem__")
self.__dict__.pop(key)

f = Foo("nick")
print(f["name"]) #获取属性, 执行__getitem__方法
f["age"] = 18 #设置属性,执行__setitem__方法
print(f.__dict__)
del f["name"] #删除属性,执行__delitem__方法
print(f.__dict__)

  

输出结果

  执行__getitem__
nick
执行__setitem__
{'name': 'nick', 'age': 18}
执行__delitem__
{'age': 18}

  

三、__str__,__repr__,__format__

__str__是控制改变对象的字符串显示

print(obj)/'%s'%obj/str(obj)时,实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串,如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类(object)中的__str__

例子1

  class Foo:
def __str__(self):
return "控制打印对象时的显示形式"

f = Foo()
print(f) #输出结果: 控制打印对象时的显示形式

  

分析:这里打印对象直接调用了被重新定义的__str__方法

例子2

  class Foo:
def __str__(self):
return "控制打印对象时的显示形式"

f = Foo()
a = str(f)
print(a) #输出结果: 控制打印对象时的显示形式

  

分析:这里的str(object)也是调用了__str__方法

例子3

  
  class Foo:
def __str__(self):
return "控制打印对象时的显示形式"

f = Foo()
print("%s"%f) #输出结果: 控制打印对象时的显示形式

  

分析:这里的“%s”%f也是调用了__str__方法

__repr__也是显示对象的名字方式,用repr(object)或者“%r”%object会调用__repr__方法

repr 是str的备胎,但str不能做repr的备胎

例子4

  class Foo:

def __str__(self):
return "控制打印对象时的显示形式"

def __repr__(self):
print("在执行repr")
return "repr Foo"
pass
f = Foo()
print("%r"%f)
print(f)

  

输出结果

  
  在执行repr
repr Foo
控制打印对象时的显示形式

  

分析:这里print("%r"%f) 调用重新定义的__repr__方法,print(f)调用__str__方法

例子5

  
  class Foo:

def __str__(self):
return "控制打印对象时的显示形式"

def __repr__(self):
print("在执行repr")
return "repr Foo"
pass
f = Foo()
print(repr(f))

  

输出结果

  在执行repr
repr Foo

  

例子6

  
  class Foo:

# def __str__(self):
# return "控制打印对象时的显示形式"

def __repr__(self):
print("在执行repr")
return "repr Foo"
pass
f = Foo()
print(f)

  

输出结果

  在执行repr
repr Foo

  

分析:如果要调用__str__方法,首先在本类中查找有没有__str__方法,如果没有就找本类有没有__repr__方法,如果有就执行__repr__方法,不再借用父类的__str__方法。所以repr 是str的备胎,但str不能做repr的备胎。

例子7

  
  class Foo:

def __str__(self):
return "控制打印对象时的显示形式"

# def __repr__(self):
# print("在执行repr")
# return "repr Foo"
pass
f = Foo()
print(repr(f)) #输出结果 <__main__.Foo object at 0x002EB550>

  

分析:要调用__repr__方法,本类没有,直接借用父类的__repr__方法,而不执行__str__方法。所以repr 是str的备胎,但str不能做repr的备胎。

__format__

自定制格式化字符串__format__,

  format_dic = {
"ymd":"{0.year}{0.month}{0.day}",
"dmy":"{0.day}:{0.month}:{0.year}",
"mdy":"{0.month}-{0.day}-{0.year}"
}

class Foo:

def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day

def __format__(self, format_spec):
if not format_spec or format_spec not in format_dic:
format_spec = "ymd"
fmt = format_dic[format_spec]
return fmt.format(self)

f = Foo(2018,8,20)
print(format(f))
print(format(f,"dmy"))
print(format(f,"mdy"))
print("{:mdy}".format(f))

  

输出结果

  
  2018820
20:8:2018
8-20-2018
8-20-2018

  

分析:调用format方法自定制字符串格式化,这里调用__format__方法

四、__slots__

__slots__:其实就是将类中的名称锁定,实例化对象,只可以赋值和调用,不可以删除属性和增加新的属性

1、__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(也就是意味着所有实例只有一个数据属性)

2、使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)

3、字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。

4、应用场景:当实例化几万个对象的时候,每个对象都会生成一个名称空间__dict__,而每一个名称空间都会各自占用一个内存,造成内存的浪费,用 __slots__,不用再产生每个对象的 dict 了,省内存,对象的 dict 都统一用类的 dict,属性都是用 slots 给定义的

  
  class Foo:

__slots__ = ["name","age"] #在类中定义属性"name"、"age"

f1 = Foo()
f1.name = "nick" #首先要进行赋值,不赋值调用会出错
print(f1.name)
# f1.gender = "female" # 新增__slots__之外的属性会报错
# del f1.age #删除属性也会报错

  

五、__doc__

__doc__显示文档注释信息,文档注释信息无法继承给子类。

例子

  
  class Foo:
"""
我是文档注释
"""
pass

f = Foo()
print(f.__doc__) #输出结果 : 我是文档注释

  

例子2

  
  class Foo:
"""
我是文档注释
"""
pass

class Son(Foo):
pass

s = Son()
print(s.__doc__) #输出结果:None

  

六、__module____class__

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

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

例子1

  
  class Foo:

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

f = Foo("nick")
print(f.__module__) #当执行文件为当前文件时,__module__ = __main__
#输出结果:__main__
print(f.__class__) #输出当前操作的类名是什么
#输出结果:<class '__main__.Foo'>

  

例子2

文件结构

  ├── index.py #执行文件
│ ├── test
│ │   ├── a.py  

a.py内容:

  
  class Bar:
def __init__(self):
self.name = "nicholas"

  

index.py内容:

 from test.a import  Bar

class Foo:

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

b = Bar()
print(b.name) #输出结果 nicholas
print(b.__module__) #输出结果 test.a ,表示当前操作的类在test.a下
print(b.__class__) #表示当前操作的类名是<class 'test.a.Bar'>

  

七、 __del__析构方法

析构方法,当对象在内存中被释放时,自动触发执行。即清除释放内存的方法。

这个是在回收实例化对象时触发执行的方法,删除对象的属性不会触发__del__方法

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

例子1

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

def __del__(self):
print("我执行啦!")

f = Foo("nick")
print("-----1")
del f.name
print("-----2") #这里是先执行print("-----1")然后执行print("-----2") ,
# 执行del f.name只是删除对象字典的"name"属性,并不会触发__del__方法

  

输出结果

  
  -----1
-----2
我执行啦!

  

例子2

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

def __del__(self):
print("我执行啦!")

f = Foo("nick")
print("-----1")
del f #删除对象才能调用__del__,这里既执行了__del__方法,又删除了对象
print("-----2")

  

输出结果

  -----1
我执行啦!
-----2

  

例子3

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

def __del__(self):
print("我执行啦!")

f = Foo("nick")
import time
time.sleep(2)

  

输出结果


 我执行啦!

  

分析:这里在程序结束时,python解释器自动回收内存,执行了__del__方法

典型的应用场景:

创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中

当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源。

例子

  
  class Foo:

def __del__(self):
print("我执行了")

f = Foo()
f.file = open("test.txt") #打开文件,在操作系统中打开了一个文件,
# 拿到了文件操作符存在了内存中
del f.file #删除了内存中的文件操作符,但是并未关闭操作系统中的文件,
# 这时需要在__del__中加入定制f.file.close(),关闭操作系统的文件
print("-----1")
#最后程序结束python解释器自动执行内存回收,执行了__del__方法

  

输出结果

  -----1
我执行了

  

Python之路(第二十六篇) 面向对象进阶:内置方法的更多相关文章

  1. Python之路(第二十九篇) 面向对象进阶:内置方法补充、异常处理

    一.__new__方法 __init__()是初始化方法,__new__()方法是构造方法,创建一个新的对象 实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法 __ ...

  2. Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类

    一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...

  3. Python之路(第二十五篇) 面向对象初级:反射、内置方法

    [TOC] 一.反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它 ...

  4. Python之路(第二十四篇) 面向对象初级:多态、封装

    一.多态 多态 多态:一类事物有多种形态,同一种事物的多种形态,动物分为鸡类,猪类.狗类 例子 import abc class H2o(metaclass=abc.ABCMeta): ​ def _ ...

  5. Python之路(第二十二篇) 面向对象初级:概念、类属性

    一.面向对象概念 1. "面向对象(OOP)"是什么? 简单点说,“面向对象”是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式.俗话说,条条大路通罗马,也就说我们使 ...

  6. Python之路(第十六篇)xml模块、datetime模块

    一.xml模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单, xml比较早,早期许多软件都是用xml,至今很多传统公司如金融行业的很多系统的接口还主要 ...

  7. Python之路【第六篇】:socket

    Python之路[第六篇]:socket   Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字&quo ...

  8. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  9. python中有两个下划线__的是内置方法,一个下划线_或者没有下划线的可能是属性,也可能是方法,也可能是类名

    python中有两个下划线__的是内置方法,一个下划线_或者没有下划线的可能是属性,也可能是方法,也可能是类名,如果在类中定义的就是类的私有成员. >>> dir(__builtin ...

随机推荐

  1. git flow分支管理

    阅读目录 两种核心分支 三种临时分支 Git Flow流程示例代码 Git Flow工具 分支命名规范 总结 git flow是Vincent Driessen提出了一个分支管理的策略,非常值得借鉴. ...

  2. 分享一个 Java String split 快速分割的方法

    java中string.split() 方法比较强大,但是split()方法采用正则表达式,速度相对会慢一点, 其实大多数场景下并不需要使用正则表达式,下面分享一个不使用正则表达式分隔字符串的方法. ...

  3. js中的全局变量

    在js中有3中声明全局变量的方式 第一种使用var+变量名,在方法外部声明: var msg; //默认值undefined $(function(){ setmsg(); showmsg(); }) ...

  4. 基本数据类型(dict)

    05. 基本数据类型(dict)内容:1. 字典的简单介绍2. 字典增删改查和其他操作3. 字典的嵌套⼀. 字典的简单介绍字典(dict)是python中唯⼀的⼀个映射类型.他是以{ }括起来的键值对 ...

  5. SystemC_Basic

    1.http://baike.baidu.com/view/1018980.htm 百度百科介绍的很好,举例很清晰. 2.SystemC的三个基本进程:SC_METHOD,SC_THREAD,SC_C ...

  6. 二分图 最小点覆盖 poj 3041

    题目链接:Asteroids - POJ 3041 - Virtual Judge  https://vjudge.net/problem/POJ-3041 第一行输入一个n和一个m表示在n*n的网格 ...

  7. 线程 Thread Handler

    new Thread(new Runnable() { @Override public void run() { Message msg = new Message(); msg.what = 0; ...

  8. JavaScript各种继承方式(五):寄生式继承(parasitic)

    一 原理 与原型式继承完全相同,只是对父类的实例(也当作子类的实例使用)进行了增强. function create(obj){ let mango = Object.create(obj); man ...

  9. ActiveMQ之java Api

    ActiveMQ 安全机制 activemq的web管理界面:http://127.0.0.1:8161/admin activemq管控台使用jetty部署,所以需要修改密码则需要修改相应的配置文件 ...

  10. bitcode?

    今天在网站上看到一篇关于第三方库不包含bitcode就会报错的文章,感觉剖析得很详细,分享出来,希望可以对iOS初入门者有所帮助.下面我们就一起来看看吧. 用Xcode 7 beta 3在真机(iOS ...