Python学习6(单例模式模块包)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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文件,也就变成包了
包的命名也要遵循规则,只能出现字母数字下划线
导入包
- 直接使用包名.模块模块名导入指定的模块。
- 使用from xxx import xxx 方式导入指定模块。
- 使用from 包名.模块名 import 类/函数 导入指定包里的模块中的类或者函数
- from 包名.模块名 import * 导入模块下的内容
- from .模块 import 类/函数 . 表示当前包下,和相对路径差不多,有时候会出问题
- 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 <包名>命令可以用来卸载指定的第三方资源包。
以上是关于Python学习6(单例模式模块包)的主要内容,如果未能解决你的问题,请参考以下文章