正文:本文展示一些高级的Python设计结构和它们的使用方法。在日常工作中,你可以根 推导式(Comprehensions)如果你已经使用了很长时间的Python,那么你至少应该听说过列表推导(list comprehensions)。这是一种将for循环、if表达式以及赋值语句放到单一语句中的一种方法。换句话说,你能够通过一个表达式对一个列表做映射或过滤操作。 一个列表推导式包含以下几个部分:
举个例子,我们需要从一个输入列表中将所有大于0的整数平方生成一个新的序列,你也许会这么写: 很简单是吧?但是这就会有4行代码,两层嵌套外加一个完全不必要的append操作。而如果使用filter、lambda和map函数,则能够将代码大大简化: 嗯,这么一来代码就会在水平方向上展开。那么是否能够继续简化代码呢?列表推导能够给我们答案:
列表推导式被封装在一个列表中,所以很明显它能够立即生成一个新列表。这里只有一个type函数调用而没有隐式调用lambda函数,列表推导式正是使用了一个常规的迭代器、一个表达式和一个if表达式来控制可选的参数。 另一方面,列表推导也可能会有一些负面效应,那就是整个列表必须一次性加载于内存之中,这对上面举的例子而言不是问题,甚至扩大若干倍之后也都不是问题。但是总会达到极限,内存总会被用完。 针对上面的问题,生成器(Generator)能够很好的解决。生成器表达式不会一次将整个列表加载到内存之中,而是生成一个生成器对象(Generator objector),所以一次只加载一个列表元素。 生成器表达式同列表推导式有着几乎相同的语法结构,区别在于生成器表达式是被圆括号包围,而不是方括号: 这比列表推导效率稍微提高一些,让我们再一次改造一下代码: 除非特殊的原因,应该经常在代码中使用生成器表达式。但除非是面对非常大的列表,否则是不会看出明显区别的。 下例使用zip()函数一次处理两个或多个列表中的元素: 再来看一个通过两阶列表推导式遍历目录的例子:
装饰器(Decorators)装饰器为我们提供了一个增加已有函数或类的功能的有效方法。听起来是不是很像Java中的面向切面编程(Aspect-Oriented Programming)概念?两者都很简单,并且装饰器有着更为强大的功能。举个例子,假定你希望在一个函数的入口和退出点做一些特别的操作(比如一些安全、追踪以及锁定等操作)就可以使用装饰器。 装饰器是一个包装了另一个函数的特殊函数:主函数被调用,并且其返回值将会被传给装饰器,接下来装饰器将返回一个包装了主函数的替代函数,程序的其他部分看到的将是这个包装函数。 语法糖@标识了装饰器。 好了,让我们回到刚才的例子。我们将用装饰器做一些更典型的操作: 当你写下如下代码时: 意味着你分开执行了以下步骤: 装饰器函数中的代码创建了一个新的函数(正如此例中的wrapper函数),它用 *args 和 **kwargs 接收任意的输入参数,并且在此函数内调用原函数并且返回其结果。你可以根据自己的需要放置任何额外的代码(例如本例中的计时操作),新创建的包装函数将作为结果返回并取代原函数。 当编译器查看以上代码时,function()函数将会被编译,并且函数返回对象将会被传给装饰器代码,装饰器将会在做完相关操作之后用一个新的函数对象代替原函数。 装饰器代码是什么样的?大部分的例子都是将装饰器定义为函数,而我发觉将装饰器定义成类更容易理解其功能,并且这样更能发挥装饰器机制的威力。 对装饰器的类实现唯一要求是它必须能如函数一般使用,也就是说它必须是可调用的。所以,如果想这么做这个类必须实现__call__方法。 这样的装饰器应该用来做些什么?它可以做任何事,但通常它用在当你想在一些特殊的地方使用原函数时,但这不是必须的,例如: 译者注: 一个更实际的例子:
上下文管理库(ContextLib)contextlib模块包含了与上下文管理器和with声明相关的工具。通常如果你想写一个上下文管理器,则你需要定义一个类包含__enter__方法以及__exit__方法,例如: 完整的例子在此: 上下文管理器被with声明所激活,这个API涉及到两个方法。 利用@contextmanager装饰器改写上面那个例子: 看上面这个例子,函数中yield之前的所有代码都类似于上下文管理器中__enter__方法的内容。而yield之后的所有代码都如__exit__方法的内容。如果执行过程中发生了异常,则会在yield语句触发。 描述器(Descriptors)描述器决定了对象属性是如何被访问的。描述器的作用是定制当你想引用一个属性时所发生的操作。 构建描述器的方法是至少定义以下三个方法中的一个。需要注意,下文中的instance是包含被访问属性的对象实例,而owner则是被描述器修辞的类。
译者注:对于instance和owner的理解,考虑以下代码: 上例中,instance指的是temp,而owner则是Temperature。 LazyLoading Properties例子: 描述器很好的总结了Python中的绑定方法(bound method)这个概念,绑定方法是经典类(classic classes)的实现核心。在经典类中,当在一个对象实例的字典中没有找到某个属性时,会继续到类的字典中查找,然后再到基类的字典中,就这么一直递归的查找下去。如果在类字典中找到这个属性,解释器会检查找到的对象是不是一个Python函数对象。如果是,则返回的并不是这个对象本身,而是返回一个柯里化(currying function)的包装器对象。当调用这个包装器时,它会首先在参数列表之前插入实例,然后再调用原函数。 译者注: 综上,描述器被赋值给类,而这些特殊的方法就在属性被访问的时候根据具体的访问类型自动地调用。 元类(MetaClasses)元类提供了一个改变Python类行为的有效方式。 元类的定义是“一个类的类”。任何实例是它自己的类都是元类。 在上例中,我们定义了一个类demo,并且生成了一个该类的对象obj。首先,可以看到obj的__class__是demo。有意思的来了,那么demo的class又是什么呢?可以看到demo的__class__是type。 所以说type是python类的类,换句话说,上例中的obj是一个demo的对象,而demo本身又是type的一个对象。 所以说type就是一个元类,而且是python中最常见的元类,因为它使python中所有类的默认元类。 因为元类是类的类,所以它被用来创建类(正如类是被用来创建对象的一样)。但是,难道我们不是通过一个标准的类定义来创建类的么?的确是这样,但是python内部的运作机制如下:
a. Meta是元类,所以这个调用是实例化它。 那么如何确定一个类(A)的元类呢?简单来说,如果一个类(A)自身或其基类(Base_A)之一有__metaclass__属性存在,则这个类(A/Base_A)就是类(A)的元类。否则type就将是类(A)的元类。 模式(Patterns)“请求宽恕比请求许可更容易(EFAP)” 这个Python设计原则是这么说的“请求宽恕比请求许可更容易(EFAP)”。不提倡深思熟虑的设计思路,这个原则是说应该尽量去尝试,如果遇到错误,则给予妥善的处理。Python有着强大的异常处理机制可以支持这种尝试,这些机制帮助程序员开发出更为稳定,容错性更高的程序。 单例 单例是指只能同时存在一个的实例对象。Python提供了很多方法来实现单例。 Null对象 Null对象能够用来代替None类型以避免对None的测试。 观察者 观察者模式允许多个对象访问同一份数据。 构造函数 构造函数的参数经常被赋值给实例的变量。这种模式能够用一行代码替代多个手动赋值语句。 希望这篇文章能够对你现在或者之后的学习有所帮助,学习编程(python)并不难,各位可以加下群:643692991 (免费资料+视频)一起学习交流提升技术,你要知道当你成功之后,现在付出的努力都是值得的。 |
|
来自: 石头p4g54puvpz > 《python》