python基础——面向对象进阶下

1 __setitem__,__getitem,__delitem__

把对象操作属性模拟成字典的格式

想对比__getattr__(), __setattr__() 和 __deltattr__()这三个通过属性的方式的三个方法

 还有__getitem__(), __setitem__() 和 __delitem__()这三个函数, 是通过字典形式来处理属性

 字典形式使用中括号的方式获取值

 在实现__setitem__()的时候仍然需要使用__dict__来实现增值的设置

—getitem— 查看并返回一个value的值

class Foo:
def __init__(self,name):
self.name=name
def __getitem__(self, item): #需要一个返回值
print('getitem')
return self.__dict__[item] #返回一个值value的值
f=Foo('egon')
# print(f.name) #值是f.name="egon"
print(f['name']) #触发getitem运行 把name传给item
print(f.__dict__) #查看字典里面的值

输出结果为:

getitem
egon
{'name': 'egon'}

__setitem__设置字典里面的值

class Foo:
def __init__(self,name):
self.name=name def __setitem__(self, key, value):
print('setitem')
self.__dict__[key]=value f=Foo("egon")
f["age"]=18 #触发 setitem 并打印setitem 并没有执行下面的值
print(f.__dict__) #查看字典里面的值

输出结果为:

setitem
{'name': 'egon', 'age': 18}

  

 __delitem__ 删除字典里面的值

class Foo:
def __init__(self,name):
self.name=name
def __delitem__(self, key):
print('delitem')
self.__dict__.pop(key) f=Foo('egon')
# del f['age'] #del.f.age
print(f.__dict__) #删除后打印一下

输出结果为:

{'name': 'egon'}

2 _slots_

1.__slots__是什么:

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

2.引子:

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

3.为何使用__slots__:

字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__

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

4.注意事项:

__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。

关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。

slots_不会产生一个名称空间,省内存,属性只能设置_slots_规定的属性

class People:
_slots_=["name","age"] #可以加值
p=People()
p.name="karina" #对象没有自己的字典也就意味着没有自己的名称空间
p.age="18"
print(p.name,p.age)

输出结果为:

karina 18

3 _iter_ _next_ 实现迭代器协议

 可迭代对象是有方法__iter__()

迭代器是有方法__next__()

因而可以自己构建一个类, 使得它的对象, 既是一个可迭代对象, 也是一个迭代器 

例1

from collections import Iterable,Iterator #导入模块 判断是不是可迭代对象
class Foo:
def __init__(self,start):
self.start=start def __iter__(self):
return self def __next__(self):
return 'asb' f=Foo(0)
print(next(f)) #触发_next_ f._next_()
for i in f: #res=f._iter_() #next(res)
print(i)
*目前这样的情况下会进入死循环
# print(isinstance(f,Iterable)) #判断f是不是可迭代对象
# print(isinstance(f,Iterator)) #判断f是不是迭代器

抛一个异常

# from collections import Iterable,Iterator #导入模块 判断是不是可迭代对象
# class Foo:
# def __init__(self,start):
# self.start=start
#
# def __iter__(self):
# return self
#
# def __next__(self):
# if self.start>10: #抛一个异常并 做一个判断
# raise StopIteration
# n=self.start #设定初始值 从0开始
# self.start+=1 #每次自加一次
# # return n
# f=Foo(0)
# print(next(f))
# print(next(f))
# print(next(f))
# print(next(f))
# for i in f:
# print(i)

  

列2:模拟range功能 

class Range:
def __init__(self,start,end):
self.start=start
self.end=end def __iter__(self):
return self
def __next__(self):
if self.start>self.end:
raise StopIteration
n=self.start
self.start+=1
return n
r=Range(0,2)
for i in r :
print(i)

输出结果为:

0
1
2

  

4 _doc_ 打印注释信息 

在类中最开始定义的光秃秃的字符串是类的文档信息

查看该文档信息可以使用__doc__来获取

在函数中的第一个光秃秃的字符串也是, 通过函数名来调用__doc__即可获得

另外__doc__无法被继承

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

5 __module__

  __module__和__class__是两个特殊属性

  可以通过对象点的方式获取

  __module__是获取对象所在模块的名字. __class__是获取对象所在的类

  具体代码如下

import time
print(time.time.__module__)
print(time.time.__class__)
# time
# <class 'builtin_function_or_method'="">
</class>

 

6 __del__ 析构函数

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

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

import time
class Open:
def __init__(self,filepath,mode='r',encode='utf8'):
self.f=open(filepath,mode=mode,encoding=encode) def write(self):
pass def __getattr__(self, item):
return getattr(self,item) def __del__(self): #析构函数del
print('---->del')
self.f.close() #已删除就关闭文件 做清理操作 f=Open('a.txt','r')
del f #删除时 去执行__del__
time.sleep(100)

输出结果为:

---->del

7 __enter__和__exit__

我们知道在操作文件对象的时候可以这么写

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

上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

class Foo:
def __enter__(self):
print('enter')
return "111" def __exit__(self, exc_type, exc_val, exc_tb):
print('exit')
print('exc_type',exc_type) #打印类型
print('exc_val',exc_val) #打印值
print('exc_tb',exc_tb) #打印追踪信息
return True #返回一个不为假的布尔值,代表已经出来过异常,程序不会蹦掉 # with Foo(): #res=Foo()._enter_
# pass with Foo() as obj: #res=Foo()._enter_ #obj=res #with 触发_enter 然后执行打印拿回一个返回值
print('with foo 的自代码块',obj)#再执行with的自代码块,打印的值为None
#因为obj目前是没有值,如果有返回值,obj就会返回值
raise NameError("名字属性定义") #主动抛出异常 触发 exit方法 在with的自代码中抛出异常,
# 意味着with自代码块执行完,后面不管有没有代码都不执行

输入结果为:

enter
exit
exc_type None
exc_val None
exc_tb None
enter
with foo 的自代码块 111
exit
exc_type <class 'NameError'>
exc_val 名字属性定义
exc_tb <traceback object at 0x02558058>

用途或者说好处:

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

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

8 __call__

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

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

class People:
def __init__(self,name):
self.name=name def __call__(self, *args, **kwargs):
print("call")
p=People("egon")
p() #属性直接加括号运行

输出结果为:

call

9 元类

1、所有的对象都是由类产生的,类又是有type产生的

type--->类----->对象

type成为元类,是所有类的类,利用type模拟class关键字的创建类的过程

创建一个类两方面要素 一个是类的名字,一个是名称空间定制的属性
 在python3里,所有的类都是新式类,都有继承object
 type()手动创建一个类三点:#类名 字符串形式 #类继承关系
元祖形式 #类的属性名称空间 字典类型

def run(self):
print('%s is runing'%self.name) class_name='Bar' #类名
bases=(object,) #类继承关系
class_dic={
"x":1, #类的属性名称空间
"run":run
}
Bar=type(class_name,bases,class_dic)
print(Bar)

输出结果为:

<class '__main__.Bar'>
class_name='Spam'
bases=(object,)
class_dic={
"name":"karina",
"age":18
}
Spam=type(class_name,bases,class_dic)
print(Spam)
print(Spam.__dict__)

输出结果为:

<class '__main__.Spam'>
{'name': 'karina', 'age': 18, '__module__': '__main__', '__dict__':
<attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}

  

2、自定义元类

可以写一个元类Mateclass, 它需要继承自type类

  原来的类需要关联该元类, 也就是在继承中有 metaclass=元类名字

  此时执行元类就可以生成一个对象, 也就是创建的这个类

  基于此, 就是元类中的__init__()方法创建的 类对象, 所以新加的功能只需在__init__()方法中就行

  元类的__init__()有额外三个参数, 分别是类名, 类基类, 类属性字典

  实现检查__doc__的代码如下

class MyMetaclass(type):
def __init__(self, class_name, class_bases, class_dic):
for key, value in class_dic.items():
if callable(value) and not value.__doc__:
raise Exception("{}方法内必须写入注释..".format(key)) class Foo(metaclass=MyMetaclass):
x = 1
def __init__(self, name):
self.name = name
def run(self):
'run function'
print('running')
def go(self):
print('going') 

元类可以创建类的行为:

type
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
pass
def __call__(self, *args, **kwargs):
# print(self)
obj=self.__new__(self) #产生空对象
self.__init__(obj,*args,**kwargs) #obj.name='egon'
return obj class Foo(metaclass=Mymeta):#指定元类等于Mymeta
x=1
def __init__(self,name):
self.name=name #obj.name='egon 不能有返回值
def run(self):
print("running")
f=Foo('egon')
print(f)

python基础——面向对象进阶下的更多相关文章

  1. python基础——面向对象进阶

    python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...

  2. python基础-面向对象进阶

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

  3. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  4. python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)

    python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...

  5. python基础——面向对象编程

    python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...

  6. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  7. Python基础与进阶

    1 Python基础与进阶 欢迎来到Python世界 搭建编程环境 变量 | 字符串 | 注释 | 错误消除 他只用一张图,就把Python中的列表拿下了! 使用 If 语句进行条件测试 使用字典更准 ...

  8. Python 3 面向对象进阶

    Python 3 面向对象进阶 一.    isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的 ...

  9. Python基础—面向对象(进阶篇)

    通过上一篇博客我们已经对面向对象有所了解,下面我们先回顾一下上篇文章介绍的内容: 上篇博客地址:http://www.cnblogs.com/phennry/p/5606718.html 面向对象是一 ...

随机推荐

  1. Filecoin官方更新: Q4工作进展和2018年工作计划

    ICO过后,Filecoin团队一直没有对外更新过工作计划(很多投资人都等待的不耐烦了).经过漫长的等待,在新年的第一个工作日,我们终于等来了来自于filecoin团队的声音, 这次更新真是出乎小编的 ...

  2. PHP MVC框架核心类

    PHP MVC框架核心类 现在我们举几个核心框架的例子演示:在framework/core下建立一个Framework.class.php的文件.写入以下代码: // framework/core/F ...

  3. elfinder中通过DirectoryStream.Filter实现筛选隐藏目录(二)

    今天还是没事看了看elfinder源码,发现之前说的两个版本实现都是基于不同的jdkelfinder源码浏览-Volume文件系统操作类(1), 带前端页面的是基于1.6中File实现,另一个是基于1 ...

  4. Java读取properties文件连接数据库

    先说为什么要有这种东西,或者我们为什么要用这种方式来写,先看经常用的方法,我们经常写的 package util; import java.sql.Connection; import java.sq ...

  5. java 常用正则表达式总结

    邮政编码: ^[1-9]\d{5}$ QQ号码: ^[1-9]\d{4,10}$ 或者:[1-9][0-9]{4,11} 邮箱: ^[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0- ...

  6. Linux Vim查找字符串

    一.用/和?的区别:/后跟查找的字符串.vim会显示文本中第一个出现的字符串.?后跟查找的字符串.vim会显示文本中最后一个出现的字符串.二.注意事项:不管用/还是?查找到第一个字符串后,按回车,vi ...

  7. Sublime 、NotePad++中查找匹配中文字符

    在Sublime .NotePad++中可以使用正则表达式 [\x{4e00}-\x{9fa5}] 查找匹配中文字符.

  8. beta冲刺6

    前言:此篇是补昨天凌晨的.后面有更新但是太晚了就没有即使更新.所以现在过来更新一下. 昨天的未完成: 用户测试+测试报告 目前剩下的功能点:输入内容检测 我的社团输出显示格式调整. 今天的完成: 我的 ...

  9. 数据结构基础——指针及动态内存分配(malloc)

    一.指针 C语言中的指针是一种数据类型,比如说我们用int *a;就定义了一个指针a,它指向一个int类型的数.但是这个指针是未初始化的,所以,一般的,我们都在创建指针时初始化它,以免出错,在还不吃的 ...

  10. scrapy 博客爬取

    item.py import scrapy class FulongpjtItem(scrapy.Item): # define the fields for your item here like: ...