扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
在Python中,如果我们想实现创建类似于序列和映射的类(可以迭代以及通过[下标]返回元素),可以通过重写魔法方法 __getitem__、__setitem__、__delitem__、__len__ 方法去模拟。
十余年的鄞州网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。网络营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整鄞州建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。成都创新互联从事“鄞州网站设计”,“鄞州网站推广”以来,每个客户项目都认真落实执行。
__getitem__(self,key): 返回键对应的值。
__setitem__(self,key,value): 设置给定键的值
__delitem__(self,key): 删除给定键对应的元素。
__len__(): 返回元素的数量
【注释】只要实现了 __getitem__ 和 __len__ 方法,就会被认为是序列。
这些魔术方法的原理就是:当我们对类的属性item进行下标的操作时,首先会被 __getitem__()、__setitem__()、__delitem__() 拦截,从而执行我们在方法中设定的操作,如赋值,修改内容,删除内容等等。
这个方法应该以与键相关联的方式存储值,以便之后能够使用 __setitem__ 来获取。当然,这个对象可变时才需要实现这个方法。
举个栗子:
定义一副扑克牌(不包括大小王),对牌进行洗牌,然后发牌。
Output:
【注意】 :我们会发现output中,输出了: slice(1, 3, None) ,下面给出解释。
语法:
参数说明:
slice() 函数实现切片对象,主要用在切片操作函数里的参数传递。
举两个栗子来看看:
Output:
切片原理
output
(程序员必会的 hhhhh.....)
看看slice在python3.7中是怎么描述的:
知乎自己看网页链接:
matplotlib的plot函数接受一组X和Y坐标,还可以通过color、marker和linestyle关键字传入指定的颜色、标记和线型,或者用一个表示颜色、标记和线型的格式字符串替代,两种方法是等效的。格式字符串中color、marker和linestyle可以任意排列,如'ko--','k--o','o--k'
魔法方法 (Magic Methods) 是Python中的内置函数,一般以双下划线开头和结尾,例如__ init__ 、 __del__ 等。之所以称之为魔法方法,是因为这些方法会在进行特定的操作时会自动被调用。
在Python中,可以通过dir()方法来查看某个对象的所有方法和属性,其中双下划线开头和结尾的就是该对象的魔法方法。以字符串对象为例:
可以看到字符串对象有 __add__ 方法,所以在Python中可以直接对字符串对象使用"+"操作,当Python识别到"+"操作时,就会调用该对象的 __add__ 方法。有需要时我们可以在自己的类中重写 __add__ 方法来完成自己想要的效果。
我们重写了 __add__ 方法,当Python识别"+"操作时,会自动调用重写后的 __add__ 方法。可以看到,魔法方法在类或对象的某些事件出发后会自动执行,如果希望根据自己的程序定制特殊功能的类,那么就需要对这些方法进行重写。使用魔法方法,我们可以非常方便地给类添加特殊的功能。
1、构造与初始化
__ new __ 、 __ init __ 这两个魔法方法常用于对类的初始化操作。上面我们创建a1 = A("hello")时,但首先调用的是 __ new __ ;初始化一个类分为两步:
a.调用该类的new方法,返回该类的实例对象
b.调用该类的init方法,对实例对象进行初始化。
__new__ (cls, *args, **kwargs)至少需要一个cls参数,代表传入的类。后面两个参数传递给 __ init __ 。在 __ new __ 可以决定是否继续调用 __ init __ 方法,只有当 __ new __ 返回了当前类cls的实例,才会接着调用 __ init __ 。结合 __ new __ 方法的特性,我们可以通过重写 __ new __ 方法实现Python的单例模式:
可以看到虽然创建了两个对象,但两个对象的地址相同。
2、控制属性访问这类魔法
方法主要对对象的属性进行访问、定义、修改时起作用。主要有:
__getattr__(self, name): 定义当用户试图获取一个属性时的行为。
__getattribute__(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用getattr)。
__setattr__(self, name, value):定义当一个属性被设置时的行为。
当初始化属性时如self.a=a时或修改实例属性如ins.a=1时本质时调用魔法方法self. __ setattr __ (name,values);当实例访问某个属性如ins.a本质是调用魔法方法a. __ getattr __ (name)
3、容器类操作
有一些方法可以让我们自己定义自己的容器,就像Python内置的List,Tuple,Dict等等;容器分为可变容器和不可变容器。
如果自定义一个不可变容器的话,只能定义__ len__ 和__ getitem__ ;定义一个可变容器除了不可变容器的所有魔法方法,还需要定义__ setitem__ 和__ delitem__ ;如果容器可迭代。还需要定义__ iter __。
__len__(self):返回容器的长度
__getitem__(self,key):当需要执行self[key]的方式去调用容器中的对象,调用的是该方法
__setitem__(self,key,value):当需要执行self[key] = value时,调用的是该方法
__iter__(self):当容器可以执行 for x in container:,或者使用iter(container)时,需要定义该方法
下面举一个例子,实现一个容器,该容器有List的一般功能,同时增加一些其它功能如访问第一个元素,最后一个元素,记录每个元素被访问的次数等。
这类方法的使用场景主要在你需要定义一个满足需求的容器类数据结构时会用到,比如可以尝试自定义实现树结构、链表等数据结构(在collections中均已有),或者项目中需要定制的一些容器类型。
魔法方法在Python代码中能够简化代码,提高代码可读性,在常见的Python第三方库中可以看到很多对于魔法方法的运用。
因此当前这篇文章仅是抛砖引玉,真正的使用需要在开源的优秀源码中以及自身的工程实践中不断加深理解并合适应用。
正文
你有没有想过 with 语句是什么以及我们为什么使用它呢?请阅读这篇文章!我们中的许多人在 Python 代码中一遍又一遍地看到这个代码片段: with open( 'Hi.text' , 'w' ) as f:
f.write( "Hello, there" )
但是,我们中的一些人不知道 with 有什么用,以及为什么我们需要在这里使用它。在此阅读中,您将找到关于 with 可解决的几乎所有问题。让我们开始吧!
首先,让我们考虑一下如果不使用 with 关键字我们需要做什么。在这种情况下,我们需要先打开文件并 尝试 执行 write 。不管成功与否,我们最好在 最后 关闭它,所以我们的代码将如下所示:
f = open( 'Hi.text' , 'w' )
try :
f.write( 'Hello, there' )
finally :
f.close()
那么, with 关键字有什么用呢?它只是有助于将我们的 try..finally 代码缩短为 with... 的单个语句!这就是 with 语句用法。
那么,它到底是什么?事实上, with 语句本身在 Python 中并没有什么特别之处,它只是 Python 中 上下文管理器 的一个特性。 上下文管理器 ,引用自 Python 官方文档, 是一种让您在需要时准确分配和释放资源的方法 ,或者简单来说: 当您在某些资源上做某事时缩短您的代码片段 ,这意味着您可以自己定义 with 语句的用法!
我们如何做到这一点?嗯,很简单,你只需要实现两个 魔术函数 :一个叫做 __enter__ ,另一个叫做 __exit__ 。第一种方法是编写一个实现这两个函数的类,如下所示:
class My_file :
def __init__ (self, fname):
self.fname = fname
def __enter__ (self):
self.file = open(self.fname, 'w' )
return self.file
def __exit__ (self, exc_type, exc_val, exc_trace_back):
if self.file:
self.file.close()
在这里,我们创建了一个普通的 Python 类,实现了两个魔术函数。注意这两个函数的签名: __enter__ 只接受 self ,而 __exit__ 将接受更多参数,示例中的这三个是标准形式。这样,我们就可以直接使用:
with My_file( 'hello.txt' ) as f:
f.write( 'hello, world!' )
这里的 with 语句会先调用 __init__ 构造一个新对象,然后再调用 __enter__ 方法;最后,它会在代码块完成之前触发 __exit__ 方法。所以,上面代码的大致等价如下:
myfile = My_file( 'hello.txt' )
f = myfile.__enter__()
f.write( 'hello, world!' )
myfile.__exit(...)
实现 上下文管理器 的第二种方法是通过 装饰器 ,如下:
1.你 import contextmanager from contextlib
2.你写一个函数来实现你想要的 with 语句。
3.在函数上方添加一个装饰器 @contextmanager 。
4.使用你的 with your_function !
根据上面的介绍,让我们写一个 装饰器上下文管理器 !
from contextlib import contextmanager
@contextmanager
def my_file_open (fname):
try :
f = open(fname, 'w' )
yield f
finally :
print( 'Closing file' )
f.close()
with file_open( 'hi.txt' ) as f:
f.write( 'hello world' )
@contextmanager
def closing (f):
try :
f.write( "Finish writing" )
finally :
f.close()
with closing(open( "hi.text" )):
f.write( "hello world" )
例如,在上面的代码中,我们可以直接调用 with close(your_way_of_getting_resource) ,在你下面写的代码块即将完成之前( f.write("hello world") ),它会执行 try..finally 我们在上面定义的块。另一个是使用 suppress 工具。我们知道,在很多情况下,如果我们尝试获取一些资源,很可能在打开文件时会出现 FileNotFoundException 等错误。在某些情况下,我们希望捕获错误或抑制错误,以便程序继续正常运行。 suppress 是我们可以抑制警告的一种方式。你需要做的就是弄清楚你想要抑制哪个异常,并编写 with suppress(your_choice_of_exception) ,Python 将从这里开始处理它。在其他情况下,您可能只想在输入 with 代码块时执行某些操作。在这种情况下, nullcontext 对你来说会很方便。 nullcontext 只会返回你在 __enter__ 函数中定义的东西,而不会做任何其他事情。如果您在 Python 中处理 async 操作以访问资源,则 aclosure 是处理这种情况的实用工具。
总结
本文介绍了 with 语句的一些基本概念和用法及其底层工作原理。还有很多有趣的东西,请查看 Python 的 contextlib 文档。最后,祝您能像往常一样快乐学习和快乐编码!
链接:
你还有什么想要补充的吗?
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流