Lai Yonghao (http://laiyonghao.com) previously posted two blog articles (http://blog.csdn.net/lanphaday/article/details/6065896,http://blog.csdn.net/lanphaday/article/details/6074095) talked about Python-message, a self-made Python library of subscription/release models, however, it does not fully introduce all its features. Since then, I have spoken many times at the Pearl River Delta technology Salon (http://techparty.org), although there are audio and video, but the retrieval is not good. During the Spring Festival holiday, I had to rethink some Python-message design issues and modify the form of the subscribed callback function. Therefore, the new version will be incompatible with v0.1.x, the new version uses v0.2.x (interestingly, the previous two articles use the v0.0.x interface, which is compatible with v0.2.x, so you do not need to change it ). Today, I will introduce all the features supported by Python-message v0.2 in this article. Install
Python-message has been submitted to pypi, so installation using easy_install or Pip is supported. To use the former, run the following command (administrator privilege may be required ):
easy_install -U message
Initial Experience
After the installation is complete, you can write a simple example to experience message-oriented programming:
import messagedef hello(name): print 'hello, %s.'%namemessage.sub('greet', hello) # subscribemessage.pub('greet', 'lai') # publish
The sub function in the message module provides an interface for subscribing to a topic. It accepts two parameters: the first is the topic, and the topic can use strings as long as it is collections. all sub-classes of hashable can be used, such as tuple. The second parameter is a callback function, and its form parameter should be accepted through message. the real parameters released by the pub () function generally do not return values. The first parameter of the pub function is the topic, which can be followed by several indefinite parameters and keyword parameters. All these parameters will be passed into the callback function of the topic. Therefore, the output of the above Code is:
hello, lai.
Cancel subscription
Canceling a topic subscription is obviously a general requirement. Add the following code to the end of the code segment in the previous section and execute the code again. The output is the same, because no callback function is subscribed to for the subsequent topic:
message.unsub('greet', hello) # unsubscribemessage.pub('greet', 'lai') # publish
Unsub () of Python-message supports canceling the subscription directly in the callback function. This feature facilitates one-time subscription. The sample code is as follows:
import messagedef hello(name): print 'hello, %s.'%name message.unsub('greet', hello)message.sub('greet', hello)message.pub('greet', 'lai')message.pub('greet', 'u cann\'t c me.')
Stop message transmission
The biggest change between Python-message v0.1.x and v0.2.x is here. In v0.1.x, a condition is added to the Message callback function to support message suspension: the first parameter context receives a control variable from the message. For example, the preceding Hello (name) function must be hello (context, name. discontinued sets the true value to abort message transmission. However, in real applications, it is rare to abort message transmission. Therefore, the context parameter is not only exhausting your fingers, but also often generates a warning for pylint/pyflaks. So in v0.2.x, I made up my mind to remove the context parameter, so how can I stop message transmission? See the following code:
import messagedef hello(name): print 'hello %s' % name ctx = message.Context() ctx.discontinued = True return ctxdef hi(name): print 'u cann\'t c me.'message.sub('greet', hello)message.sub('greet', hi)message.pub('greet', 'lai')
As you can see, Python-message uses the return value of the callback function to stop message transmission, because the same message may be processed by multiple callback functions, therefore, the return value of the callback function is meaningless and can be used to stop message transmission. However, the Code above is a bit complicated. The callback function Hello () can be abbreviated as follows:
def hello(name): print 'hello %s' % name return message.Context(discontinued = True)
Change call order
Python-message synchronously calls the callback function, that is, who calls sub first and who is called first. In most cases, this can meet the requirements of the big score, but sometimes the function of the last sub is called first, so the message. sub functions are supported by a default parameter. You only need to simply add front = true when calling sub. This callback function will be inserted before all callback functions that have previously been Sub: sub ('greet ', hello, front = true ).
Warning do not change messages
Because Python has always passed references, when pub () is a message, all the real parameters accepted by the message processing callback function are the same. If a callback function changes the real parameters, this will affect subsequent callback function calls, and the bug is very difficult to troubleshoot. Therefore, we solemnly warn you that although the callback function can change the real parameters at any time, it is best not to do so.
Subscribe to past messages
Python-message is not implemented in the subscription/publish mode. It is a library for message programming, so it can "subscribe to past messages ". This requirement may seem uncommon. Let me give you a simple example: you develop a key function bar () in the library Foo, which requires that some resources are "actually available" when called ", the real availability of resources means that the database has been connected to a database. Because it is not the duty of Foo to initialize the database connection, foo needs a way to determine whether the database is available. Generally, a global number of identifiers can be agreed, however, this method is relatively dirty. Python-message implements the "bulletin board" function through the declare/retract function, so as to support "subscribing to past messages ".
Declare (topic, * a, ** kW) is used to publish a message to the "bulletin board" and can be viewed as a pub () function, all callback functions subscribed to this topic will be called. In the preceding example, when the declare () database is connected, all objects that follow the database connection will receive a notification, and the sub () function is the topic only after the database connection is ready for a period of time, it will also be called immediately when sub () is used to "subscribe to past messages ". If the database connection fails after a period of time (for example, when the database is down), you can undo the message on the bulletin board, which requires the retract (topic) function.
In addition to the declare/retract function pairs, there are two auxiliary functions get_declarations ()/has_declaration (topic) it is used to retrieve all the topics in the "announcement board" and query whether a topic is on the "announcement board". Is it convenient?
Degraded to observer Mode
The subscription/publish mode is the superset of the observer mode. It does not focus on who published the message or who processes the message. But sometimes we want a class to more easily subscribe to/publish messages, that is, to degrade to the observer mode. Python-message also provides support. See the following code:
from message import observabledef greet(people): print 'hello, %s.'%people.name@observableclass Foo(object): def __init__(self, name): print 'Foo' self.name = name self.sub('greet', greet) def pub_greet(self): self.pub('greet', self)foo = Foo('lai')foo.pub_greet()
Python-message provides the class decoration function observable (), which provides Sub, unsub, pub, declare, retract, and other methods for any class, their usage is similar to that of global functions.
Topic naming skills
Although observable does not seem pythonic enough, I personally do not like it, but one undeniable advantage is that it basically simplifies the topic name conflict problem: because different observable class instances have different message systems.
Because I prefer to use message directly. sub () and other functions, so I think it is good to learn from the package naming policy of Java/actionscript3. For example, define the message topic constant Foo = 'com. googlecode. python-message.FOO ', so that multiple libraries define the foo constant at the same time is not prone to conflict. In addition, you can use UUID as follows:
uuid = 'bd61825688d72b345ce07057b2555719'FOO = uuid + 'FOO'