基础部分:企业真题
python# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: 14、python实现单例模式
# Description: 单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象,
# 都是指向同一个内存地址,仅仅只有一个实例(只有一个对象)。实现单例模式的手段有很多种,但总的
# 原则是保证一个类只要实例化一个对象,下一次再实例的时候就直接返回这个对象,不再做实例化的操作。
# 所以这里面的关键一点就是,如何判断这个类是否实例化过一个对象。
# Author: zhaoyaowei
# Date: 2023/3/29 23:43
# -------------------------------------------------------------------------------
# 方法一:通过模块导入
"""
基本原理:借用了模块导入时的底层原理实现。
当一个模块(py文件)被导入时,首先会执行这个模块的代码,然后将这个模块的名称空间加载到内存。
当这个模块第二次再被导入时,不会再执行该文件,而是直接在内存中找。
于是,如果第一次导入模块,执行文件源代码时实例化了一个类,那再次导入的时候,就不会再实例化。
"""
import threading
# 方法二:通过类绑定方法
class Student:
"""
@classmethod修饰符对应的函数不需要实例化,
不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,
可以来调用类的属性,类的方法,实例化对象等
原理:类的绑定方法是第二种实例化对象的方式,
第一次实例化的对象保存成类的数据属性 _instance,
第二次再实例化时,在get_singleton中判断已经有了实例对象,
直接返回类的数据属性 _instance
"""
_instance = None # 记录实例化对象, 属性默认为类属性,可直接被类本身调用
def __init__(self, name, age): # self: 表示实例化的地址id
self.name = name
self.age = age
# 类方法(不需要实例化类就可以被类本身调用)
@classmethod
def get_singleton(cls, *args, **kwargs): # cls:表示没用被实例化的类本身
if not cls._instance:
cls._instance = cls(*args, **kwargs)
return cls._instance
# 补充:该方式实现的单例模式有一个明显的bug;原因在于若不通过绑定类的方法实例化对象,而是直接通过类名加括号实例化对象,就不是单例模式了
s1 = Student.get_singleton("tom", 2)
s2 = Student.get_singleton("tom", 2)
print(s1, s2, s1 is s2) # <__main__.Student object at 0x102f80fa0> <__main__.Student object at 0x102f80fa0> True
print(s1.__dict__, s2.__dict__) # {'name': 'tom', 'age': 2}
# 方法三:通过__new__
class Student:
"""
原理:和方法2类似,将判断的实现方式,从类的绑定方法中转移到类的__new__中
思路都是判断类有没有实例,有则直接返回,无则实例化并保存到_instance中。
__new__ 方法:使用 类名()创建对象时,Python解释器首先会调用object基类提供__new__方法为对象分配空间
作用有两个:(1)在内存中为对象分配空间 (2)返回对象的引用
若获取到对象的引用后,将引用作为第一个参数,传递给__init__方法;否则不会调用init
__init__ 方法:(1)对象初始化 (2)定义实例属性
"""
_instance = None
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
# if cls._instance:
# return cls._instance # 有实例,直接返回
# else:
# cls._instance = super().__new__(cls) # 没有实例,则new一个实例并保存
# return cls._instance # 返回给init,再实例化一次
if not cls._instance: # 简写
cls._instance = super().__new__(cls)
return cls._instance
# 补充:这种方式可以近乎完美地实现单例模式,但是依然不够完美。不完美的地方在于没有考虑到并发的极端情况下,有可能多个线程同一时刻实例化对象。
s1 = Student("tom", 3)
s2 = Student("tom", 3)
print(s1, s2, s1 is s2) # <__main__.Student object at 0x102de9c40> <__main__.Student object at 0x102de9c40> True
print(s1.__dict__, s2.__dict__) # {'name': 'tom', 'age': 3}
# 方法三优化版:
class Student:
_instance = None
_lock = threading.RLock() # 加互斥锁方法
def __new__(cls, *args, **kwargs):
if cls._instance: # 如果已经有单例,则不再抢锁,避免IO等待
return cls._instance
# 只有第一个抢到锁的线程实例化一个对象,并保存在_instance中,
# 同一时刻抢锁的其他线程再抢到锁后,不会进入判断if not cls._instance,
# 直接返回保存在_instance的对象
with cls._lock: # 使用with语法,方便抢锁和释放锁
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
# 方法四:函数装饰器
def singleton(cls):
_instance = {} # 采用字典,可以装饰多个类实现单例模式
def inner(*args, **kwargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs)
return _instance.get(cls)
return inner
# 逻辑:实例化对象时,将类对象作为参数传值给singleton(),再将函数执行完成的返回值反馈回类
@singleton
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# def __new__(cls, *args, **kwargs): # 将方法3中的重写new搬到了函数装饰器中
# if not cls._instance:
# cls._instance = super().__new__(cls)
# return cls._instance
s1 = Student("tom", 4)
s2 = Student("tom", 4)
print(s1, s2, s1 is s2) # <__main__.Student object at 0x103119670> <__main__.Student object at 0x103119670> True
print(s1.__dict__, s2.__dict__) # {'name': 'tom', 'age': 4}
# 方法五:类装饰器
class Singleton:
"""
原理:在函数装饰器的思路上,将装饰器封装成类。
程序会实例化一个Student对象,这个对象是SingleTon的对象。
后面使用的Student本质上使用的是SingleTon的对象。
所以使用Student('tom', 5)来实例化对象,其实是在调用SingleTon的对象,会触发其__call__的执行
所以就在__call__中,判断Student类有没有实例对象了。
"""
_instance = {}
def __init__(self, cls_name):
self.name = cls_name
# 若类定义类__call__方法,则将一个类的实例化对象变成了可调用对象
# Student('tom', 5) == Student.__call__('tom', 5)
def __call__(self, *args, **kwargs):
if self.name not in Singleton._instance:
Singleton._instance[self.name] = self.name(*args, **kwargs)
return self._instance.get(self.name)
@Singleton # 相当于Student = SingleTon(Student),即Student是SingleTon的实例对象
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
s1 = Student("tom", 5)
s2 = Student("tom", 5)
print(s1, s2, s1 is s2) # <__main__.Student object at 0x100915550> <__main__.Student object at 0x100915550> True
print(s1.__dict__, s2.__dict__) # {'name': 'tom', 'age': 5} {'name': 'tom', 'age': 5}
python# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: 反转一个整数,如-123,-321
# Description:
# Author: zhaoyaowei
# Date: 2023/4/1 20:51
# -------------------------------------------------------------------------------
def reverse_integer1(x):
if x >= 0:
# 如果是正数,直接反转
rev_x = int(str(x)[::-1])
else:
# 如果是负数,先反转绝对值,再加上负号
rev_x = -int(str(abs(x))[::-1])
return rev_x
def reverse_integer2(x):
sign = 1 if x >= 0 else -1
x = abs(x)
rev_x = int(str(x)[::-1])
return sign * rev_x
print(reverse_integer2(123)) # 输出:321
print(reverse_integer2(-123)) # 输出:-321
print(reverse_integer2(120)) # 输出:21
python# -*- coding: utf-8 -*-#
# -------------------------------------------------------------------------------
# Name: 设计实现遍历目录与子目录,抓取.pyc文件
# Description:
# Author: zhaoyaowei
# Date: 2023/4/1 21:18
# -------------------------------------------------------------------------------
import os
import fnmatch
def find_pyc_files(dir_path):
pyc_files = []
for root, dirs, files in os.walk(dir_path):
for file in files:
if fnmatch.fnmatch(file, '*.pyc'):
pyc_files.append(os.path.join(root, file))
return pyc_files
print(os.getcwd())
pyc_files = find_pyc_files('/Users/zhaoyaowei/Desktop/project/InterviewQuestions/Python基础')
print(pyc_files)
本文作者:赵耀伟
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!