Pulpcode

捕获,搅碎,拼接,吞咽

0%

python中全局变量的正确打开方式

在python中使用单例模式非常的“容易”。

你在一个模块中初始化一个对象,然后去引用这个对象就行了。因为python中万物皆对象,哪怕是一个包(package),也可以当作一个对象。但是这种方式并不好,因为你的代码会看上去非常耦合,所以我从来不建议把包当成一个对象,你仅仅当成一个包就可以了。我再解释一下我的意思,就是你不应该直接从一个包中import一个对象,虽然你可以这么做。你应该import进来一个类,然后通过这个类,来创建对象,这才是单例模式正确的使用方式。而且对于IDE来说,那种从包中导入的对象,因为是动态的,所以你goto define也是找不到的。

而且如果你明白了我的意思,这些来来回回传递的对象,当你想要把一个函数封装出来单独写测试时,你会发现要把这些对象当做上下文当做传入的时候,简直头疼的要死。

下面将通过三个例子,来说明我的观点,第一个例子是我认为python日志的正确使用方式,第二个是tornado中是如何使用ioloop这个全局对象的,第三个例子是我认为的一个项目的配置文件应该使用的方式。

日志的使用方式

我现在接手的项目,这个web服务的日志就是我说的那样,他们在一个包中初始化了日志对象,比如这个叫main_logger, 那个叫biz_logger,然后到处引用这些对象。

实际上我自己的代码中,获取日志的方式简单有粗暴:

1
logger = logging.getLogger(__name__)

然后你在一个统一的地方为这个__name__配置handler就行了。而且实际上的工作量要比你想象的少很多,因为像”business.handler”,这样的name是可以继承”business”的日志配置的。你设计好包的格式,然后配置他们的日志打印方式,对于单测,只要以另一种方式初始化这些logger就行了,甚至可以不管,让他们使用root默认。
因为你的代码并没有“动态耦合”。

tornado中的ioloop

还记得你怎么写tornado的代码吗?

1
tornado.ioloop.instance().start()

我们可以去看tornado的ioloop源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@staticmethod
def instance():
"""Returns a global `IOLoop` instance.
Most applications have a single, global `IOLoop` running on the
main thread. Use this method to get this instance from
another thread. In most other cases, it is better to use `current()`
to get the current thread's `IOLoop`.
"""
if not hasattr(IOLoop, "_instance"):
with IOLoop._instance_lock:
if not hasattr(IOLoop, "_instance"):
# New instance after double check
IOLoop._instance = IOLoop()
return IOLoop._instance

注意这里加了一个线程锁,相当于在类中维护了这个单例对象,你可以把这个例子用在你的单例对象中。

配置文件的使用方式

我的配置也是使用单例的方式,载入到服务中,然后instance去引用它。

当然我的配置类,可以有各种方式初始化其中的值,比如用json,用yaml,用conf文件,等等。。

需要注意的是,不要给你的单例对象写构造函数(init),因为即使是单例模式的对象,也会每次调用你的构造函数,防止你每次获取单个例都刷新了所有东西。而且按照java中的思路,单例模式本来就应该隐藏构造函数的。

python中我建议两种单例模式的实现,一种是:

1
2
3
4
5
6
7
8
9
10
class Singleton(object):
"""
python单例模式
"""
INSTANCE = None

def __new__(cls, *args, **kwargs):
if not cls.INSTANCE:
cls.INSTANCE = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls.INSTANCE

继承此类就可以了。

1
2
3
4
5
6
7
8
9
10
def singleton(cls, *args, **kw):
instances = {}
def _singleton():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return _singleton

@singleton
xxx

然后装饰到相应的类上就可以了。