汇率转换器
""" 一个货币转换器,支持货币汇率实时转换,汇率使用 https://finance.google.cn/finance/converter 谷歌的服务 """ import unittest import re from parameterized import parameterized, param from app.apis.fliggy.utils import LogManager, RequestClient, decorators, RedisManager from app import config as app_config class CurrencyConverter(object): _rate_pattern = re.compile('<span class=bld>(\S*?) .*?</span>') _redis = None _log = LogManager('CurrencyConverter').get_logger_and_add_handlers() def __init__(self, from_currency, to_currency='CNY'): """ :param from_currency: 需要被转换的货币 :param to_currency: 需要兑换成的货币 """ self._from_currency = from_currency self._to_currency = to_currency self._rate = None if not self._redis: # 使用数据库7 self.__class__._redis = RedisManager(app_config.redis_host, port=app_config.redis_port, db=7, password=app_config.redis_password).get_redis() self._redis_key_name = 'rate:{}_{}'.format(self._from_currency, self._to_currency) @decorators.handle_exception(3) # 发生错误后重试三次 def _acquire_rate_from_google_finance(self): """从谷歌网站实时请求和解析出汇率""" url = 'https://finance.google.cn/finance/converter' params = { 'a': 1, 'from': self._from_currency, 'to': self._to_currency, 'meta': '' } resp = RequestClient().request_with_proxy('get', url, params=params) self._rate = self._rate_pattern.search(resp.text).group(1) def get_rate(self): """获取汇率,汇率优先使用reids,redis中不存在的汇率则从google实时获取,获取后放入redis中设置1小时过期""" if not self._redis.exists(self._redis_key_name): self._log.debug('开始从google获取汇率') self._acquire_rate_from_google_finance() rate = self._rate if rate: self._redis.set(self._redis_key_name, rate) self._redis.expire(self._redis_key_name, 60 * 60) return float(rate) else: self._log.error('从google获取汇率失败') raise Exception('从google获取汇率失败') else: self._log.debug('开始从redis中获取汇率') return float(self._redis.get(self._redis_key_name).decode('utf8')) class _Test(unittest.TestCase): @classmethod def setUpClass(cls): cls.log = LogManager('test').get_logger_and_add_handlers() @parameterized.expand([param('USD'), param('CNY', to_currency='USD') ]) def test_from_usd_to_cny(self, from_currency, to_currency='CNY'): """ 测试美元和人民币之间的转换 :return: """ converter = CurrencyConverter(from_currency, to_currency) rate = converter.get_rate() self.assertIsNotNone(rate, msg='获取的汇率错误') self.log.debug('从 {} 转换为 {} 的汇率是 --> {}'.format(from_currency, to_currency, rate)) if __name__ == '__main__': unittest.main()
反对极端面向过程编程思维方式,喜欢面向对象和设计模式的解读,喜欢对比极端面向过程编程和oop编程消耗代码代码行数的区别和原因。致力于使用oop和36种设计模式写出最高可复用的框架级代码和使用最少的代码行数完成任务,致力于使用oop和设计模式来使部分代码减少90%行,使绝大部分py文件最低减少50%-80%行的写法。