文章目录
python—反射和单例模式
反射
有些时候你知道一个字符串数据类型的名字,你向直接调用,但是调不到
使用反射
- 反射对象的 实例变量
- 反射一个类的静态变量/绑定方法/其他方法
- 模块中的所有变量
被导入的模块
当前执行的py文件
# # 用字符串数据类型的名字 来操作这个名字对应的函数/实例鸟朦胧/各种方法
name ='alex'
age = 123
n = input('>>>')
# 有些时候你知道一个字符串数据类型的名字,你向直接掉用,但是掉不到
# 使用反射
# 1. 反射对象的 实例变量
# 2. 反射一个类的静态变量/绑定方法/其他方法
# 3. 模块中的所有变量
# 被导入的模块
# 当前执行的py文件
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def nihao(self):
print('nihapo')
alex = Person('alex', 83)
wusir = Person('wusir', 84)
print(alex.name)
print(wusir.name)
ret = getattr(wusir, 'name') # 通过字符串name直接反射到属性wusir对象的属性name
print(ret)
# # 通过字符串直接反射到对应的地址
# # 我们无法通过字符串来把他当作类名方法名调用,这样反射后就得到对应的地址
class Payment:
pass
class Alipay(Payment):
def __init__(self, name):
self.name = name
def pay(self, money):
dic = {
'uname':'用户名','price':money}
# 想办法调用支付宝支付吧dic纯过去
print(f'{self.name}通过支付宝支付{money}成功')
class WeChat(Payment):
def __init__(self, name):
self.name = name
def pay(self, money):
dic = {
'uname': '用户名', 'price': money}
# 想办法调用支付宝支付吧dic纯过去
print(f'{self.name}通微信支付{money}成功')
class QQpay(Payment):
def __init__(self, name):
self.name = name
def pay(self, money):
dic = {
'uname': '用户名', 'price': money}
# 想办法调用支付宝支付吧dic纯过去
print(f'{self.name}通qq支付{money}成功')
ali = Alipay('小明')
ali.pay(300)
import sys
# 归一化设计
def pay(name, price, way):
obj_name = getattr(sys.modules['__main__'], way) # way传入的是一个字符串,通过字符串去反射对应的函数名
obj = obj_name(name) # 执行way字符串对应的函数
obj.pay(price)
# if way == 'WeChat':
# obj = WeChat(name)
# obj.pay(price)
# elif way == 'Alipay':
# obj = Alipay(name)
# obj.pay(price)
pay('alex', 400, 'Alipay')
pay('alex', 400, 'WeChat')
pay('alex', 400, 'QQpay')
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def nihao(self):
print('nihao ')
a = A('li', 22)
re = getattr(a, 'name')
print(re)
getattr(a, 'nihao')()
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
pass
a = A('li', 22)
print(hasattr(a, 'namw')) # False
print(hasattr(a, 'name')) # True
if hasattr(a, 'name'):
print(getattr(a, 'name'))
callable() # 判断一个东西是否能调用
# 作业1
class Authentic:
def __init__(self, name, age):
self.name = name
self.age = age
def register(self):
print('注册')
def login(self):
print('登录')
lst = [('登录', 'login'), ('注册', 'register')]
# 循环这个列表
# 显示 序号 用户要做的操作
# 用户输入序号
# 你通过序号找到对应的login或者register方法
# 先实例化
# 调用对应的方法,完成登录或者注册功能
for i in range(len(lst)):
print(i, ':', lst[i][0])
n = int(input())
auth = Authentic('xiaoli', 18)
if hasattr(auth, lst[n][1]):
getattr(auth, lst[n][1])()
# 作业2
class User:
def __init__(self, name, pwd):
self.name = name
self.pwd = pwd
def eat(self):
print('eat')
def sleep(self):
pass
# 用户输入名和密码
# 实例化对象
# 用户输入任意内容:
# 如果是属性名 打印属性值
# 方法 调用
# 什么都不是 什么都不做
name = input('用户名:')
pwd = input('密码:')
user = User(name, pwd)
if hasattr(user, name):
getattr(user, name)()
else:
print(name)
单例模式
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例
而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案
。
单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的共有函数用于创建或获取它本身的静态私有对象。
cls和self
cls就是当前类名,习惯上写为cls
self时当前类的一个实例化对象
# 两个装饰器
# @classmethod
# @ staticmethod
# 一些内置的魔术方法
# __new__
# __call__
# __len__
# __eq__
# __str__
# __repr__
# classmethod
class Goods:
__discount = 0.8 # 私有属性
def __init__(self):
self.__price = 5
self.price = self.__price * self.__discount
# 定义了一个方法,默认传self,但是没有用
# def set_discount(self, new_discount):
@classmethod # 把一个对象绑定的方法,修改成一个类方法
def set_discount(cls, new_discount):
# Goods.__discount = new_discount
# classmethog 用cls和goods都可以,但是减一用cls,因为类名会改变
cls.__discount = new_discount
# 调用类方法时可以不用实例化
# 在方法中仍然可以引用类中的静态变量
# 什么时候用?
# 定义了一个方法,默认传self,但是没有用
# 你在这个方法中用到了当前类名
Goods.set_discount(0.6) # 类方法可以通过类名调用,也可以通过对象名调用
apple = Goods()
print(apple.price)
# # 修改折扣0.6
# apple.set_discount(0.6)
#
# apple2 = Goods()
# print(apple2.price)
import time
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
time_str = time.localtime()
y = time_str.tm_year
m = time_str.tm_mon
d = time_str.tm_mday
return cls(y, m, d)
date = Date.today()
print(date.year, date.month, date.day)
# @staticmethod 被装饰的方法会成为一个静态方法
# def login():
# print('login')
class User:
@staticmethod
# 本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加@staticmethod装饰器
def login():
print('login')
# 在函数内部既不会用来self,也不会用到cls
User.login()
单例模式推导
import time
import threading
class Singleton(object):
__instance = None # 静态字段、类变量
lock = threading.RLock()
# 初始化对象
def __init__(self, name):
self.name = name
# 创建一个空对象,还未初始化
# 先执行__new__
# 创建对象
def __new__(cls, *args, **kwargs):
# 进锁之前加判断,防止已经实例化后,隔一段时间又实例化时再进入锁而浪费时间。因为开锁和释放锁都需要消耗时间
if cls.__instance:
return cls.__instance
with cls.lock:
if not cls.__instance:
time.sleep(0.2) # 多线程就会出问题,都在这儿等,所以要加把锁
cls.__instance = object.__new__(cls)
return cls.__instance
obj1 = Singleton('alex')
obj2 = Singleton('alex2')
print(obj1, obj2)
print(obj1.name) # alex2
print(obj2.name) # alex2
# 上边的方式如果是多线程就会出问题
def func():
obj = Singleton('xx')
print(obj)
for i in range(10):
t = threading.Thread(target=func)
t.start()
time.sleep(60) # 执行其他代码后又要实例化,则会又进锁,浪费时间。因为前边已经实例化好了,所以在进入锁之前在加一个判断
obj = Singleton('xx')
标准单例模式
import threading
class Singleton(object):
__instance = None
lock = threading.RLock()
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if cls.__instance:
return cls.__instance
with cls.lock:
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
最简单的单例模式
模块导入的方式
single.py
# 最简单的单例模式
# 模块导入的方式
class Baby:
def __init__(self, name, close):
self.name = name
self.close = close
baby = Baby('小李', '红毛衣')
if __name__ == '__main__':
print(baby.name, baby.close) # 小李 红毛衣
xxx.py
# from 单例 import baby 其他文件导入 都是同一个baby内存地址
from day24.single import baby
print(baby.name, baby.close) # 小李 红毛衣
baby.name = '老王'
print(baby.name, baby.close) # 老王 红毛衣