Python学习6(单例模式、模块、包)

单例模式

举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

这里用两个私有化的变量来控制单例的产生
在new方法中,用instance变量来控制只能产生一块内存地址
在init方法中,用first变量来控制这个内存地址的对象是否已经被赋值了,如果已经赋值了,那么再创建对象的时候就不能进行改变了
这样保证了只能产生一个对象,只能在这个对象基础上进行更改,而不能新建一个对象

如果去掉is_first变量,那么只有一个内存地址,但是新建对象可以对内存地址中的内容进行更改,即可以通过init方法更改属性;加上这个变量判断以后,就不能进行对象的创建了

# 实例化一个单例
class Singleton(object):
    # 私有化
    __instance = None
    __is_first = True

    # 正常情况下,会调用new方法创建实例,而如果想阻止这个操作,就需要在new方法里实现
    # 这里判断这个类的实例对象是否已经存在,如果不存在可以创建,如果存在了就返回这个实例对象
    def __new__(cls, age, name):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self, age, name):
        if self. __is_first: # 不会再创建第二个对象
	        self.age = age
	        self.name = name
	        Singleton. __is_first = False


a = Singleton(18, "张三")
b = Singleton(28, "张三")
print(a)  # <__main__.Singleton object at 0x000001D6AAF544E0>
print(b)  # <__main__.Singleton object at 0x000001D6AAF544E0>

print(a.age) # 18
print(b.age) # 18

a.age = 19
print(b.age)    # 19

模块

在Python中有一个概念叫做模块(module)。

说的通俗点:模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块

比如我们经常使用工具 random,就是一个模块。使用 import random 导入工具之后,就可以使用 random 的函数。

好处:
1.提高代码的可复用,可维护性,一个模块编写完毕后,可以很方便的在其他项目中导入
2.解决了命名冲突问题,不同模块中相同命名不会冲突

在这里插入图片描述

导入模块

导入模块有四种方式

import 模块名

import 模块1,模块2,...  # 导入方式

模块名.函数名()  # 使用模块里的函数

注意:必须加上模块名调用
因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名

from 模块名 import 功能名

有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以用下面方法实现:

from 模块名 import 函数名1,函数名2....

不仅可以引入函数,还可以引入一些全局变量、类等

注意:通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。也就是说假如模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。

from 模块名 import *

把一个模块的所有内容全都导入到当前的命名空间也是可行的,调用的时候也不需要加模块名字,只需使用如下声明:

from modname import *

注意:这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

import 模块名 as 别名 / from 模块名 import 功能名 as 别名

In [1]: import time as tt  # 导入模块时设置别名为 tt

In [2]: time.sleep(1)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-07a34f5b1e42> in <module>()
----> 1 time.sleep(1)

NameError: name 'time' is not defined

In [3]: 

In [3]: tt.sleep(1)  # 使用别名才能调用方法

In [4]: 

In [4]: from time import sleep as sp  # 导入方法时设置别名

In [5]: sleep(1)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-5-82e5c2913b44> in <module>()
----> 1 sleep(1)

NameError: name 'sleep' is not defined

In [6]: 

In [6]: sp(1)  # 使用别名才能调用方法

__name__

需要注意,在导入的时候会将模块的内容加载,所以如果模块中有测试代码的会,也会被执行
所以为了能达到测试的目的,又在其他项目中导入时不会执行测试代码,需要如下操作:
在实际开中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如:

test1.py

def add(a,b):
    return a+b

# 这段代码应该只有直接运行这个文件进行测试时才要执行
# 如果别的代码导入本模块,这段代码不应该被执行
ret = add(12,22)
print('测试的结果是',ret)

demo.py

import test1.py   # 只要导入了tets1.py,就会立刻执行 test1.py 代码,打印测试内容

为了解决这个问题,python在执行一个文件时有个变量__name__.在Python中,当直接运行一个py文件时,这个py文件里的__name__值是__main__,据此可以判断一个一个py文件是被直接执行还是以模块的形式被导入。

def add(a,b):
    return a+b

if __name__ == '__main__':  # 只有直接执行这个py文件时,__name__的值才是 __main__
    # 以下代码只有直接运行这个文件才会执行,如果是文件被别的代码导入,下面的代码不会执行
    ret = add(12,22)
    print('测试的结果是',ret)

在当前模块中执行的时候,__name__的值是__main__。
而在导入该模块的文件中运行的时候,该模块的__name__的值是该模块名
所以加上__name__ == 'main’这样一个判断语句,可以保证测试代码只在该模块自己执行的时候执行

pycharm中直接输入mian,就会自动生成这句话

自定义模块

除了使用系统提供的内置模块以外,我们还能自己写一个模块供自己的程序使用。一个py文件就是一个模块,所以,自定义模块很简单,基本上相当于创建一个py文件。但是,需要注意的是,如果一个py文件要作为一个模块被别的代码使用,这个py文件的名字一定要遵守标识符的命名规则

使用from <模块名> import *导入一个模块里所有的内容时,本质上是去查找这个模块的__all__属性,将__all__属性里声明的所有内容导入。如果这个模块里没有设置__all__属性,此时才会导入这个模块里的所有内容。

模块里以一个下划线_开始的变量和函数,是模块里的私有成员,当模块被导入时,以_开头的变量默认不会被导入。但是它不具有强制性,如果一个代码强行使用以_开头的变量,有时也可以。但是强烈不建议这样使用,因为有可能会出问题。

看下面例子:
test1.py:模块里没有__all__属性

a = 'hello'
def fn():
    print('我是test1模块里的fn函数')

test2.py:模块里有__all__属性,规定了哪些能够被import * 导入(只是*不能导入,但是可以单独导入其他内容)

x = '你好'
y = 'good'
def foo():
    print('我是test2模块里的foo函数')
__all__ = ('x','foo')

test3.py:模块里有以_开头的属性,即私有属性

m = '早上好'
_n = '下午好'
def _bar():
    print('我是test3里的bar函数')

导入并调用

from test1 import *
from test2 import *
from test3 import *

print(a)
fn()

print(x)
# print(y) 会报错,test2的__all__里没有变量 y
foo()


print(m)
# print(_n)  会报错,导入test3时, _n 不会被导入

import test3
print(test3._n)  # 也可以强行使用,但是强烈不建议

在自定义模块时,需要注意一点,自定义模块名不要和系统的模块名重名,否则会出现问题!

一个模块就是一个 py 文件,在 Python 里为了对模块分类管理,就需要划分不同的文件夹。多个有联系的模块可以将其放到同一个文件夹下,为了称呼方便,一般把 Python 里的一个代码文件夹称为一个包。

包和文件夹的区别,可以看到创建包以后里面会自带一个init文件,但是文件里没有任何内容
文件夹里一般放的都是非python文件,包里面放的是py文件
在文件夹里面创建一个__init__的py文件,也就变成包了

包的命名也要遵循规则,只能出现字母数字下划线
在这里插入图片描述

导入包

  1. 直接使用包名.模块模块名导入指定的模块。
  2. 使用from xxx import xxx 方式导入指定模块。
  3. 使用from 包名.模块名 import 类/函数 导入指定包里的模块中的类或者函数
  4. from 包名.模块名 import * 导入模块下的内容
  5. from .模块 import 类/函数 . 表示当前包下,和相对路径差不多,有时候会出问题
  6. from 包名 import * 只会导入__init__文件中允许访问的模块,如果没有写__all__= [],那么都不能访问,一般不会这样导入包

__init__文件

导入包的时候,默认调用__init__.py文件,执行文件中的内容,加载文件中的函数
调用这个文件中的内容,不需要加模块名(__init__),直接包名加函数名或者类名就可以了

__init__.py 控制着包的导入行为。__init__.py为空仅仅是把这个包导入,不会导入包中的模块。可以在__init__.py文件中编写内容。

可以在newmsg里创建__init__.py文件,在该文件里导入指定的内容。
在这里插入图片描述

在__init__.py文件里编写代码:

from . import sendmsg  # 导入指定的模块    . 代表的是当前文件夹

test.py文件里的代码

import newmsg # 导入时,只需要输入包名即可。在包名的__init__.py文件里,导入了指定模块
newmsg.sendmsg.sendm_msg()  # 可以直接调用对应的方法
# newmsg.recvmsg.recv_msg()   不可以使用 recvmsg 模块,因为 __init__.py文件里没有导入这个模块

也可以使用__init__.py文件,结合__all__属性,导入包里的所有模块。

在newmsg包里的__init__.py文件里编写代码:

__all__ = ["sendmsg","recvmsg"]  # 指定导入的内容

test.py文件代码:

from newmsg import *  # 将newmsg里的__inint__.py文件里,__all__属性对应的所有模块都导入
sendmsg.sendmsg()
recvmsg.recvmsg()

循环导入出现的问题

A模块需要导入B模块,B模块需要导入A模块

执行A的时候需要导入B,而在导入B的时候又需要导入A,那么就会导致循环导入,而出错

那么如何解决呢?
1.重新定义一下架构
2.将导入的语句放在函数里面
3.把导入语句放在模块的最后

sys模块

表示python自身的运行环境

import sys
sys.path # 模块的查找路径
sys.version # 版本
sys.argv # 传递给Python脚本的命令行参数列表,运行程序时的参数
sys.exit(code) # 让程序以指定的退出码结束

sys.stdin # 标准输入。可以通过它来获取用户的输入
sys.stdout # 标准输出。可以通过修改它来百变默认输出
sys.stderr # 错误输出。可以通过修改它来改变错误删除

sys.argv # 传递给Python脚本的命令行参数列表,运行程序时的参数
就和java中,给main函数传递的args一样。
在这里插入图片描述

print(sys.argv)   # ['C:/start/包.py', '100', 'hello']     

time模块

time模块不仅可以用来显示时间,还可以控制程序,让程序暂停(使用sleep函数)
重点time.time()、sleep()、strftime()

print(time.time())  # 获取从1970-01-01 00:00:00 UTC 到现在时间的秒数
print(time.strftime("%Y-%m-%d %H:%M:%S")) # 按照指定格式输出时间
print(time.asctime()) #Mon Apr 15 20:03:23 2019   #
print(time.ctime()) # Mon Apr 15 20:03:23 2019    # # 将时间戳转成字符串

t = time.time()
print(time.ctime(t)) # 将时间戳转成字符串
print(time.localtime(t))  # 将时间戳转成元组的形式
# time.struct_time(tm_year=2022, tm_mon=7, tm_mday=14, tm_hour=18, tm_min=26, tm_sec=44, tm_wday=3, tm_yday=195, tm_isdst=0)
print(time.localtime(t).tm_hour)  # 18
print(time.mktime(time.localtime(t))) # 1657794504.0  将元组转成时间戳

print(time.strptime('2022/7/14', '%Y/%m/%d'))  # 将字符串的时间转换成元组形式
# time.struct_time(tm_year=2022, tm_mon=7, tm_mday=14, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=195, tm_isdst=-1)
print('hello')
print(time.sleep(3)) # 让线程暂停10秒钟
print('world')

datatime模块

datetime模块主要用来显示日期时间,这里主要涉及 date类,用来显示日期;time类,用来显示时间;datetime类,用来显示日期时间;timedelta类用来计算时间差。

import datetime

print(datetime.date(2020, 1, 1))  # 创建一个日期
print(datetime.time(18, 23, 45)) # 创建一个时间
print(datetime.datetime.now())  # 获取当前的日期时间
print(datetime.datetime.now() + datetime.timedelta(3))  # 计算三天以后的日期时间

random模块

random 模块主要用于生成随机数或者从一个列表里随机获取数据。

print(random.random())  # 生成 [0,1)的随机浮点数
print(random.uniform(20, 30))  # 生成[20,30]的随机浮点数
print(random.randint(10, 30))  # 生成[10,30]的随机整数,包含结尾
print(random.randrange(20, 30))  # 生成[20,30)的随机整数,可以加步长,不包含结尾数
print(random.choice('abcdefg'))  # 从列表里随机取出一个元素
print(random.sample('abcdefghij', 3)) # 从列表里随机取出指定个数的元素

ll = [1,2,3,4,5]
random.shuffle(ll) # 随即打乱
print(ll)

hashlib模块

hashlib是一个提供字符加密功能的模块,包含MD5和SHA的加密算法,具体支持md5,sha1, sha224, sha256, sha384, sha512等算法。该模块在用户登录认证方面应用广泛,对文本加密也很常见。
base64这个加密算法是可逆的,提供的一般都是不可逆的

import hashlib

# 待加密信息
str = '这是一个测试'

# 创建md5对象
hl = hashlib.md5('hello'.encode(encoding='utf8'))
print('MD5加密后为 :' + hl.hexdigest())

h1 = hashlib.sha1('123456'.encode())
print(h1.hexdigest())
h2 = hashlib.sha224('123456'.encode())
print(h2.hexdigest())
h3 = hashlib.sha256('123456'.encode())
print(h3.hexdigest())
h4 = hashlib.sha384('123456'.encode())
print(h4.hexdigest())

msg = '123456'
print(hashlib.sha3_256(msg.encode('utf-8'))) # <_sha3.sha3_256 object at 0x000001C517AA6600>

第三方包

对第三方包的管理主要包含查找、安装和卸载三个部分的操作。

使用 pip install <包名>命令可以安装指定的第三方资源包。

pip install ipython # 安装ipython包

使用 install 命令下载第三方资源包时,默认是从 pythonhosted下载,由于各种原因,在国内下载速度相对来说比较慢,在某些时候甚至会出现连接超时的情况,我们可以使用国内镜像来提高下载速度。

如果只是想临时修改某个第三方资源包的下载地址,在第三方包名后面添加 -i 参数,再指定下载路径即可,格式为pip install <包名> -i <国内镜像路径>

pip install ipython -i https://pypi.douban.com/simple

除了临时修改pip的下载源以外,我们还能永久改变pip的默认下载路径。

在当前用户目录下创建一个pip的文件夹,然后再在文件夹里创建pip.ini文件并输入一下内容:

[global]
index-url=https://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com

常见国内镜像

阿里云 https://mirrors.aliyun.com/pypi/simple/
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣(douban) https://pypi.douban.com/simple/
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学 https://pypi.mirrors.ustc.edu.cn/simple/

卸载

使用 pip install <包名>命令可以用来卸载指定的第三方资源包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Python 中,单例模式可以通过使用模块、装饰器或元类来实现。下面分别介绍这三种实现方式。 1. 使用模块 Python 中的模块是单例的,因为模块在程序中只会被导入一次,之后再次导入时,会直接使用已经存在的模块对象。可以利用这个特性来实现单例模式,将需要实现单例的类定义在一个模块中,然后导入该模块即可。 例如,假设我们有一个名为 `MySingleton` 的类,我们可以将其定义在一个名为 `mysingleton.py` 的模块中,并在需要使用单例的地方导入该模块。这样,无论在哪里导入该模块,都是使用同一个 `MySingleton` 实例,从而实现单例模式。 2. 使用装饰器 可以使用装饰器来将一个类变成单例模式。具体实现方式是:定义一个装饰器函数,在该装饰器函数中创建一个字典,用于保存已经创建的实例。在调用被装饰的类时,先检查该字典中是否已经存在该类的实例,如果存在,则返回已经存在的实例,否则创建新的实例,并保存到字典中。 下面是一个使用装饰器实现单例模式的示例: ```python def singleton(cls): instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class MySingleton: def __init__(self, x): self.x = x obj1 = MySingleton(1) obj2 = MySingleton(2) print(obj1.x) # 输出 1 print(obj2.x) # 输出 1 print(obj1 is obj2) # 输出 True ``` 在这个例子中,我们定义了一个名为 `singleton` 的装饰器函数,该函数接受一个类作为参数,并返回一个函数 `get_instance`。在 `get_instance` 函数中,我们首先检查字典 `instances` 中是否已经存在该类的实例。如果已经存在,则直接返回该实例,否则创建新的实例,并保存到字典中。 在定义 `MySingleton` 类时,我们使用了 `@singleton` 装饰器来将它变成单例模式。在调用 `MySingleton` 类时,实际上是调用了 `get_instance` 函数,从而实现了单例模式。 3. 使用元类 可以使用元类来定义一个类的创建方式,从而实现单例模式。具体实现方式是:定义一个继承自 `type` 的元类,重写 `__call__` 方法,在该方法中检查是否已经存在该类的实例,如果存在,则返回已经存在的实例,否则创建新的实例,并保存到字典中。 下面是一个使用元类实现单例模式的示例: ```python class Singleton(type): instances = {} def __call__(cls, *args, **kwargs): if cls not in cls.instances: cls.instances[cls] = super().__call__(*args, **kwargs) return cls.instances[cls] class MySingleton(metaclass=Singleton): def __init__(self, x): self.x = x obj1 = MySingleton(1) obj2 = MySingleton(2) print(obj1.x) # 输出 1 print(obj2.x) # 输出 1 print(obj1 is obj2) # 输出 True ``` 在这个例子中,我们定义了一个名为 `Singleton` 的元类,该元类继承自 `type` 类,并重写了 `__call__` 方法。在 `__call__` 方法中,我们首先检查字典 `instances` 中是否已经存在该类的实例。如果已经存在,则直接返回该实例,否则创建新的实例,并保存到字典中。 在定义 `MySingleton` 类时,我们使用了 `metaclass` 参数来指定该类的元类为 `Singleton`,从而将它变成单例模式。在调用 `MySingleton` 类时,实际上是调用了 `Singleton` 元类的 `__call__` 方法,从而实现了单例模式。 ### 回答2: Python单例模式是一种设计模式,用于确保一个类只有一个实例存在。在Python中,单例模式通常通过使用装饰器或元类来实现。 装饰器的实现方式是在类定义之前定义一个装饰器函数,该函数用于创建并返回一个实例。当类的实例被创建时,装饰器函数会检查是否已经存在一个实例,如果存在则返回该实例,否则创建一个新实例并返回。 元类的实现方式是定义一个继承自`type`的元类,并重写`__call__`方法。该方法在实例创建时被调用,可以在此方法中实现单例逻辑。在该方法中,可以保存一个类的实例,并在后续调用时返回该实例,确保只有一个实例存在。 无论是使用装饰器还是元类,单例模式都遵循以下原则: 1. 只能有一个实例存在,多次创建实例只返回同一个实例。 2. 实例可以全局访问,无论在哪个模块中,都可以通过调用类的方法获取实例。 3. 确保线程安全,避免多个线程同时创建实例。 由于Python的动态特性,单例模式Python中相对容易实现。但需要注意的是,单例模式可能导致全局状态的共享,增加了组件之间的耦合性,所以在使用时需谨慎考虑。在不明确需要使用单例模式的情况下,建议优先考虑其他的设计模式。 ### 回答3: 单例模式是一种创建对象的设计模式,它确保类只有一个实例,并提供全局访问点。 在Python中,实现单例模式有多种方法,下面分别介绍两种常见的方式。 1. 使用模块实现单例模式: 在Python中,模块在首次被导入时,会被解析并执行模块中的代码。因此,我们可以将需要实现单例模式的类定义在一个模块中,并在其他模块中导入该模块,确保该类只被实例化一次。示例代码如下: ```python # singleton.py class SingletonClass: def __init__(self, name): self.name = name singleton_instance = SingletonClass("Singleton Instance") # main.py from singleton import singleton_instance def main(): print(singleton_instance.name) if __name__ == "__main__": main() ``` 以上代码中,`SingletonClass`是一个需要实现单例模式的类,我们在`singleton.py`中将其实例化为`singleton_instance`,然后在`main.py`中导入并使用这个实例。 2. 使用装饰器实现单例模式: 另一种常见的实现方式是使用装饰器,通过装饰器将一个类装成单例模式。示例代码如下: ```python def singleton(cls): instances = {} def wrapper(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class SingletonClass: def __init__(self, name): self.name = name def main(): instance1 = SingletonClass("Singleton Instance 1") instance2 = SingletonClass("Singleton Instance 2") print(instance1.name) print(instance2.name) if __name__ == "__main__": main() ``` 以上代码中,我们定义了一个名为`singleton`的装饰器函数,将需要实现单例模式的类`SingletonClass`作为参数传递给装饰器。在`wrapper`函数中,通过判断类是否已经存在实例,如果不存在则创建一个新的实例,并将其存储到`instances`字典中。每次调用`SingletonClass`时,实际上是调用了`wrapper`函数并返回相应的实例。 通过以上两种方式,我们可以实现Python中的单例模式,确保某个类只有一个实例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值