引言

我学过多门编程语言,却变得越来越迷惑。我们知道C语言,每个变量都需要声明变量类型,在函数调用的时候也必须保证参数类型一致。而python 的变量不需要声明类型,且甚至不许要提前声明,python极大的降低了程序开发的门槛(牺牲性能换来的)。本文着重解决2个问题:

  • Python如何实现不需要声明数据类型
  • python语言本身体现了哪些设计模式?

本文借由第一个问题探究python语言设计的底层实现,借由第二个问题探究python语言设计时的高层设计模式思想。

二、Python语言本身体现了哪些设计模式?

  • 单例模式(Singleton Pattern):Python的模块就是一种单例模式,因为Python在导入模块时,会缓存已经导入的模块。因此,任何时候导入同一模块都会得到相同的实例。
  • 装饰器模式(Decorator Pattern):Python的装饰器是一种非常强大的模式,可以通过装饰器在不修改被装饰函数的情况下,添加新的功能。
  • 工厂模式(Factory Pattern):Python的工厂函数可以看做一种工厂模式,工厂函数接收参数,根据参数返回特定的实例对象。通过使用classmethodstaticmethod等语法来实现工厂设计模式。同时,还可以使用第三方库比如factory_boy来实现工厂模式。
  • 观察者模式(Observer Pattern):Python中的事件机制可以看做是一种观察者模式,当一个事件发生时,所有订阅该事件的观察者都会收到通知。Python 的很多标准库模块都采用了观察者模式的实现方式,例如Queue.Queuethreading.Event等。
  • 策略模式(Strategy Pattern):Python中的函数可以看做是一种策略模式的实现,不同的函数实现了不同的策略,在不同的场景下使用不同的策略函数。
  • 迭代器模式(Iterator Pattern):Python中的迭代器是一个非常常见的模式,可以对不同的数据结构进行统一的遍历操作。for ... in ... 循环语句就是基于迭代器模式实现的。Python 的内置类型如列表、元组、字典等都可以使用迭代器来遍历
  • 适配器模式(Adapter Pattern):Python的函数式编程特性可以看做是一种适配器模式的实现,通过函数的返回值进行适配,将不同的接口进行统一。Python 标准库的collections.Iterable抽象基类就是一种适配器模式的实现,它可以将任意一个对象转换为可迭代的对象。
  • 组合模式(Composite Pattern):Python 的内置类型中,列表和字典都是基于组合模式实现的。列表中的元素可以是任意类型的对象,包括其他列表,字典中的值也可以是任意类型的对象,包括其他字典。

单例模式(Singleton Pattern)

具体来说,当我们导入一个模块时,python会检查该模块是否已经被加载,如果没有被加载,python会加载并执行该模块的代码,并将该模块的命名空间加入sys.modules中,以便在所有引用该模块的地方都能够访问到该模块。

由于python只会导入一个模块的一份实例,所以我们可以在模块中定义一个类作为单例对象,如果该类已经被实例化过了,我们就直接返回该实例,否则就创建一个新的实例,并将其保存到类的一个类属性中,以便下次使用。

具体代码实现和示例如下所示:

# singleton.py
class Singleton:_instance = Nonedef __new__(cls, *args, **kwargs):if cls._instance is None:cls._instance = super().__new__(cls)return cls._instance# main.py
from singleton import Singletons1 = Singleton()
s2 = Singleton()assert s1 is s2 # True

在上面的示例中,我们定义了一个Singleton类作为单例对象,其中_instance是一个类属性,用于保存单例实例。在__new__方法中,我们首先判断该类的_instance属性是否为空,如果为空,就调用父类的__new__方法创建一个新的实例,否则直接返回已有的实例。

在主程序中,我们通过导入singleton模块来使用Singleton类,并创建了两个对象s1s2,我们可以通过s1 is s2来判断这两个对象是否是同一个实例,如果是,则说明单例模式生效

装饰器模式(Decorator Pattern)

装饰器模式可以用在很多地方,如计时器、log日志、权限控制、缓存、异常处理等。下面是一个简单的装饰器示例:

def my_decorator(func):def wrapper(*args, **kwargs):print('Before the function is called.')result = func(*args, **kwargs)print('After the function is called.')return resultreturn wrapper@my_decorator
def say_hello(name):print(f"Hello {name}!")
# #等价如下程序
# def say_hello(name):
#     print(f"Hello {name}!")
# say_hello = my_decorator(say_hello)say_hello("Alice")

上述代码中,定义了一个装饰器my_decorator,它接受一个函数func作为参数,并返回一个新的函数wrapper。在新函数中,先输出一句话表示函数被调用之前,然后执行原函数,并获取返回结果。最后再输出一句话表示函数被调用之后,并返回原函数的返回结果。

通过在函数定义前加上@my_decorator,就能够装饰函数say_hello,使得它在被调用前后能够自动输出一些信息。

工厂模式(Factory Pattern)

classmethod和staticmethod

在Python中通过使用@classmethod@staticmethod等语法来实现工厂设计模式,实际上是利用Python的装饰器语法来实现。装饰器的用法和原理上面已经讲过了。

在使用classmethodstaticmethod这两个装饰器时,我们可以用它们来定义类级别的方法,而不需要先创建一个实例。这些方法可以用来创建、初始化、返回对象等,这正是工厂模式所要完成的任务。

我们可以通过@staticmethod装饰器来定义一个静态方法,该方法不需要实例化对象,可以直接通过类名来调用。静态方法通常用来处理独立于对象状态的操作。例如:

class MyClass:@staticmethoddef my_staticmethod():print("This is a static method")MyClass.my_staticmethod()  # This is a static method

我们也可以通过@classmethod装饰器来定义一个类方法,该方法的第一个参数是类本身,通常被命名为cls。类方法可以在不实例化对象的情况下操作类和对象。例如:

class MyClass:count = 0@classmethoddef increase_count(cls):cls.count += 1MyClass.increase_count()
MyClass.increase_count()
print(MyClass.count)  # 2

上述示例中,我们定义了一个名为increase_count的类方法,它通过cls参数来操作类属性count,从而实现对该属性的累加。我们可以直接使用类名调用这个类方法来进行操作。

例子

工厂模式通常包含两个部分:工厂和产品。工厂是一个负责创建产品的类或函数,它可以接收参数来决定要创建的产品类型。产品是被创建出来的实例对象,它们都有共同的接口或基类,从而保证了客户端代码可以统一调用不同种类的产品。

在Python中,我们可以定义一个名为Product的基类,然后在它的子类中定义不同种类的产品,并在一个名为Factory的工厂类中实现根据参数创建对应产品的逻辑。

下面是一个简单的示例代码:

class Product:def use(self):passclass ProductA(Product):def use(self):print("Product A is being used.")class ProductB(Product):def use(self):print("Product B is being used.")class Factory:@classmethoddef create_product(cls, product_type):if product_type == "A":return ProductA()elif product_type == "B":return ProductB()else:raise ValueError("Invalid product type")product_a = Factory.create_product("A")
product_a.use()  # Output: Product A is being used.product_b = Factory.create_product("B")
product_b.use()  # Output: Product B is being used.

上述代码中,我们定义了一个名为Product的基类,它包含一个名为use()的抽象方法。ProductAProductB都是Product的子类,它们分别实现了use()方法。

然后,我们定义了一个名为Factory的工厂类,它有一个名为create_product()的类方法。这个方法根据传入的参数来创建不同种类的产品,并返回创建好的产品实例。如果传入的参数无效,我们将抛出一个ValueError异常。

最后,我们通过调用Factory.create_product()方法来创建不同的产品实例,并调用它们的use()方法来演示其功能。

工厂模式可以帮助我们隐藏复杂的对象创建过程,同时提供一个简单的接口来创建不同的对象类型。在Python中,通过使用@classmethod@staticmethod等语法,可以很方便地实现工厂模式。

策略模式(Strategy Pattern)

策略模式是一种设计模式,它定义了一系列算法,将每个算法封装到具有共性的多个类中,使它们可以互相替换。在 Python 中,由于函数的动态特性,我们可以直接将实现了不同算法的函数作为不同的策略,然后将它们作为参数传入一个共同的处理函数中,从而实现同一组数据的不同处理方式。

例如,假设我们需要对一组数字进行排序,我们可以定义一个函数sort(numbers, strategy),其中numbers表示待排序的数字列表,strategy表示排序策略,可以是冒泡排序、快速排序、归并排序等等。我们可以定义多个不同的排序函数,然后将它们作为参数传递到sort函数中,从而实现不同的排序策略。

这样做的好处是,我们可以根据需要动态地选择不同的排序策略,而不需要修改sort函数的实现。同时,我们也可以进一步抽象出一个排序策略的接口,以便于更加灵活地替换策略函数。

迭代器模式(Iterator Pattern)

Python 中的迭代器模式体现在迭代器对象(Iterator Object)上。迭代器对象是用于遍历集合或序列(如列表、元组、字典等)的一种对象,在遍历时,它可以记录当前遍历的位置,以便于在下一次调用时继续遍历。

在 Python 中,我们可以通过内置函数iter()next()来获取迭代器对象并进行一次次的遍历操作,这就是迭代器模式的实现之一。

让我们通过一个简单的例子来说明如何使用Python迭代器模式。假设我们有一个列表,要遍历其中所有的元素:

my_list = [1, 2, 3, 4, 5]# 通过 iter() 函数获取迭代器对象
my_iterator = iter(my_list)# 通过 next() 函数遍历迭代器对象中的元素
print(next(my_iterator)) # 1
print(next(my_iterator)) # 2
print(next(my_iterator)) # 3
print(next(my_iterator)) # 4
print(next(my_iterator)) # 5# 当所有元素遍历完毕后,再次调用next()函数将抛出异常
print(next(my_iterator)) # StopIteration

上面的代码中,我们首先使用iter()函数获取了一个迭代器对象my_iterator,然后使用next()函数遍历这个迭代器对象中的元素。在每次调用next()函数时,迭代器对象会返回下一个元素的值,直到所有元素都被遍历完毕。当所有元素遍历完毕后,再次调用next()函数将抛出一个StopIteration异常,表示迭代已经结束。

另外,Python 还通过抽象基类(Abstract Base Class)collections.abc.Iterablecollections.abc.Iterator来规范了迭代器的实现方式。这些抽象基类提供了通用的接口,可以保证实现该接口的对象是可迭代的,并且能够被内置函数iter()使用。

使用迭代器模式的好处是,我们可以使用相同的方式遍历不同的集合或序列,而且遍历方式也可以随时改变,而不需要修改集合或序列的实现。例如,我们可以使用同样的方式遍历一个列表、一个字符串和一个文件,这样就可以使代码更加通用和灵活。

我们也可以动手自己实现一个迭代器:

class MyIterator:def __init__(self, data):self.index = 0self.data = datadef __iter__(self):return selfdef __next__(self):if self.index >= len(self.data):raise StopIterationresult = self.data[self.index]self.index += 1return result

上面的代码中,我们定义了一个名为MyIterator的迭代器类,它接受一个列表作为参数。在__init__()方法中,我们初始化了index属性和data属性,分别表示当前遍历的位置和要遍历的数据。

__iter__()方法中,我们返回了迭代器对象自身,这是迭代器模式中的典型实现方式。

最后,在__next__()方法中,我们实现了迭代器的核心逻辑。首先,我们检查当前遍历的位置是否大于等于数据的长度。如果是,则抛出一个StopIteration异常,表示迭代结束。如果不是,则返回当前位置的元素,并将位置向后移动一位。

现在,我们可以使用这个迭代器类来遍历一个列表:

my_list = [1, 2, 3, 4, 5]
my_iterator = MyIterator(my_list)for item in my_iterator:print(item)

输出结果为:

1
2
3
4
5

这个例子虽然简单,但是它显示了迭代器模式的核心思想:通过定义一个单独的迭代器类,我们可以在不修改原始数据的情况下,灵活地遍历数据,并且可以使用相同的方式遍历不同的数据类型。如果你想要深入了解如何实现更复杂的迭代器类,可以查看Python文档中的相关内容。

Python编程语言体现出的设计模式相关推荐

  1. Python再夺冠,上古语言COBOL大流行,IEEE Spectrum 2020年度编程语言排行榜出炉!...

    整理 | 屠敏 题图 | 东方 IC 出品 | CSDN 博客 领域驱动技术,技术鞭策领域. 近日,IEEE Spectrum 最新发布了 2020 年年度编程语言排行榜.IEEE Spectrum ...

  2. Python、设计原则和设计模式-创建类设计模式

    Python.设计原则和设计模式 前言 程序的目标:高内聚 低耦合 有哪些设计原则 设计原则是「高内聚.低耦合」的具体落地. 单一职责原则要求在软件系统开发.设计中,一个类只负责一个功能领域的相关职责 ...

  3. BigData:大数据开发的简介、核心知识(linux基础+Java/Python编程语言+Hadoop{HDFS、HBase、Hive}+Docker)、经典场景应用之详细攻略

    BigData:大数据开发的简介.核心知识(linux基础+Java/Python编程语言+Hadoop{HDFS.HBase.Hive}+Docker).经典场景应用之详细攻略 BigData:大数 ...

  4. python编程语言的优点-为什么一定要学习python语言

    python与人工智能 什么是人工智能 视频 阿里菜鸟无人仓 -科技-高清完整正版视频在线观看-优酷 https://v.youku.com/v_show/id_XMzgwMDEyOTE5Mg==.h ...

  5. python编程语言汇总-Python技术之书籍汇总

    近日,一直在学习Python,发现有关的书籍还是很多值得一读的,所以在此总结一下.以后慢慢去研读吧!!! Python入门 <Python编程快速上手--让繁琐工作自动化> 作者: [美] ...

  6. python在中小学教学中的应用-小学信息技术教学中进行Python 编程语言教学的策略...

    原标题:小学信息技术教学中进行Python 编程语言教学的策略 本文发表于 <数字教育> 2019年第2期(总第26期)实践案例栏目,页码:82-86.转载请注明出处. 摘 要:本文探讨在 ...

  7. 机器人编程语言python-入门篇丨使用EV3机器人,趣味学习Python编程语言~

    原标题:入门篇丨使用EV3机器人,趣味学习Python编程语言~ 你知道吗? 数据显示: 到2020年,将有超过200万个 STEAM相关领域的工作岗位: 而当谈到SETAM学习时, 却只有17%的学 ...

  8. python在中小学教学中的应用-中小学Python编程语言教学

    中小学Python编程语言教学 作为一名高中信息技术老师,被技术的发展潮流推动着,不断更新教学内容和方法,以适应快速发展的信息社会. 以前的中小学信息技术课程,老师们各显神通,身怀绝技,教PS,Fal ...

  9. 零基础可以学python吗-Python编程语言好学吗?零基础转行能学Python吗?

    Python编程语言好学吗?零基础转行能学Python吗?人工智能时代的来临催生了很多新兴行业,Python是最具代表性也是比较热门的技术之一.有人看好Python入门简单.功能强大的特性,选择转行从 ...

最新文章

  1. 使用Docker快速搭建PHP开发环境
  2. bs架构与cs架构的区别_Oracle vs Mysql--架构、sql查询执行流程及SQL解析顺序区别说明...
  3. boost::spirit模块实现利用 Karma 生成器的替代方案和内置匹配功能的测试程序
  4. WMI 使用教程_.NET 入门教程
  5. 大型网站电商网站架构案例和技术架构的示例
  6. 互联网晚报 | 2月8日 星期二 | 上海微电子交付中国首台光刻机;广东诞生全国首个万亿工业强区;东芝宣布分拆为两家公司...
  7. 量子计算机电商,量子产品系虚假宣传 为何仍能在电商平台销售?
  8. 暖心社区(2018-07-17)
  9. [转]java中的值传递和引用传递
  10. Fragment的使用
  11. 币久网好像暂停ZEC交易了,各位的ZEC币暂时不要转入币久网了
  12. Faster RCNN 网络分析及维度分析
  13. 一款超好用的企业级URL采集软件(Msray-plus)
  14. 字符串库函数(1)Strlen,strcpy,strcat,strcmp
  15. win10家庭版用户实现远程桌面解决办法
  16. 计算机错误代码0X000000be,win7电脑出现蓝屏错误0x000000BE的解决方法
  17. TPP稳定性之场景隔离和多租户
  18. 通过一张照片查对方位置
  19. 向特定计算机共享文件夹,win7共享文件夹给指定的电脑
  20. Uncaught ReferenceError: UE is not defined at zh-cn.js:8

热门文章

  1. 网络购物需谨慎 “闲鱼”与“咸鱼“仅一个链接的距离
  2. 2019个人成长计划
  3. Linux如何安装FTDI D2XX驱动
  4. window下python安装包问题小结
  5. oppo a36参数配置
  6. Android布局原理与优化
  7. uniapp 解决phoneX原生tabbar 安全区域问题
  8. 中央电大计算机网络试题,2017电大统考计算机试题及答案
  9. Thinkphp3.2 PHPMailer 发送 QQ邮箱 163邮箱
  10. 网络隔离环境下的跨网数据传输,如何保障安全性?