⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sect12.htm

📁 this is the most basic to learn python
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source: 
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:TIPython.rtf
Application Directory:c:\tools\rtf2html\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:12/31/2001
Translation Time:08:24:13
Translation Platform:Win32
Number of Output files:18
This File:Sect12.htm
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>10: Callbacks</TITLE>

<script language="JavaScript">
</script>
</head>


<BODY  BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
  <a href="http://www.MindView.net">
  <img src="mindview.gif" alt="MindView Inc." BORDER = "0"></a>
  <CENTER>
    <FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
    <!-- [ <a href="README.txt">Viewing Hints</a> ]
    [ <a href="RevisionHistory.htm">Revision History</a> ] -->
    [ <a href="http://www.mindview.net/Books/TIPython/">Book Home Page</a> ]
    [ <a href="http://www.mindview.net/Etc/MailingList.html">Free Newsletter</a> ] <br>
    [ <a href="http://www.mindview.net/Seminars">Seminars</a> ]
    [ <a href="http://www.mindview.net/CDs">Seminars on CD ROM</a> ]
    [ <a href="http://www.mindview.net/Services">Consulting</a> ]
    </FONT>
  <H2><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
  Thinking in Python<br>
  <small>Revision 0.1.2 (12/31/01) -- Incomplete and Unfinished</small></FONT></H2>
  <H3><FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans">
  by Bruce Eckel &copy;2002 MindView, Inc.</FONT></H3>
  
    <FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
     [ <a href="Sect11.htm">Previous Chapter</a> ] 
    
    [ <a href="javascript:window.location.href = 'Index.htm';">Table of Contents</a> ] 
  
        [ <a href="DocIdx.htm">Index</a> ]
        
     [ <a href="Sect13.htm">Next Chapter</a> ] 
    </FONT>
    
  </CENTER>
  </P></DIV><A NAME="_Toc476705913"></A><A NAME="_Toc534420123"></A><A NAME="Heading74"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H1 ALIGN="LEFT">
10: Callbacks</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Decoupling code behavior</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><I>Observer</I>, and a category of
callbacks called &#147;multiple dispatching (not in <I>Design
Patterns</I>)&#148; including the <I>Visitor</I> from <I>Design Patterns</I>.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_292">Add Comment</A></FONT><A NAME="_Toc462393595"></A><A NAME="_Toc476705914"></A><A NAME="_Toc534420124"></A><BR></P></DIV>
<A NAME="Heading75"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Observer</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Like the other forms of callback, this
contains a hook point where you can change code. The difference is in the
observer&#146;s completely dynamic nature. It is often used for the specific
case of changes based on other object&#146;s change of state, but is also the
basis of event management. Anytime you want to decouple the source of the call
from the called code in a completely dynamic way.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_293">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<A NAME="Index18"></A><A NAME="Index19"></A>observer pattern solves a fairly
common problem: What if a group of objects needs to update themselves when some
object changes state? This can be seen in the &#147;model-view&#148; aspect of
Smalltalk&#146;s MVC (model-view-controller), or the almost-equivalent
&#147;Document-View Architecture.&#148; Suppose that you have some data (the
&#147;document&#148;) and more than one view, say a plot and a textual view.
When you change the data, the two views must know to update themselves, and
that&#146;s what the observer facilitates. It&#146;s a common enough problem
that its solution has been made a part of the standard <B>java.util</B> library.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_294">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two types of objects used to
implement the observer pattern in Python. The
<A NAME="Index20"></A><B>Observable</B> class keeps track of everybody who wants
to be informed when a change happens, whether the &#147;state&#148; has
changed or not. When someone says &#147;OK, everybody should check and
potentially update themselves,&#148; the <B>Observable</B> class performs this
task by calling the <A NAME="Index21"></A><B>notifyObservers(&#160;)</B> method
for each one on the list. The <B>notifyObservers(&#160;)</B> method is part of
the base class <B>Observable</B>.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_295">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are actually two &#147;things that
change&#148; in the observer pattern: the quantity of observing objects and the
way an update occurs. That is, the observer pattern allows you to modify both of
these without affecting the surrounding code.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_296">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">-------------</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>Observer</B> is an
&#147;interface&#148; class that only has one member function,
<B>update(&#160;)</B>. This function is called by the object that&#146;s being
observed, when that object decides its time to update all its observers. The
arguments are optional; you could have an <B>update(&#160;)</B> with no
arguments and that would still fit the observer pattern; however this is more
general&#151;it allows the observed object to pass the object that caused the
update (since an <B>Observer </B>may be registered with more than one observed
object) and any extra information if that&#146;s helpful, rather than forcing
the <B>Observer</B> object to hunt around to see who is updating and to fetch
any other information it needs.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_297">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The &#147;observed object&#148; that
decides when and how to do the updating will be called the <B>Observable</B>.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_298">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>Observable</B> has a flag to indicate
whether it&#146;s been changed. In a simpler design, there would be no flag; if
something happened, everyone would be notified. The flag allows you to wait, and
only notify the <B>Observer</B>s when you decide the time is right. Notice,
however, that the control of the flag&#146;s state is <B>protected</B>, so that
only an inheritor can decide what constitutes a change, and not the end user of
the resulting derived <B>Observer</B> class.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_299">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Most of the work is done in
<B>notifyObservers(&#160;)</B>. If the <B>changed</B> flag has not been set,
this does nothing. Otherwise, it first clears the <B>changed</B> flag so
repeated calls to <B>notifyObservers(&#160;)</B> won&#146;t waste time. This is
done before notifying the observers in case the calls to <B>update(&#160;)</B>
do anything that causes a change back to this <B>Observable</B> object. Then it
moves through the <B>set</B> and calls back to the <B>update(&#160;)</B> member
function of each <B>Observer</B>.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_300">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">At first it may appear that you can use
an ordinary <B>Observable</B> object to manage the updates. But this
doesn&#146;t work; to get an effect, you <I>must</I> inherit from
<B>Observable</B> and somewhere in your derived-class code call
<A NAME="Index22"></A><B>setChanged(&#160;)</B>. This is the member function
that sets the &#147;changed&#148; flag, which means that when you call
<A NAME="Index23"></A><B>notifyObservers(&#160;)</B> all of the observers will,
in fact, get notified. <I>Where</I> you call <B>setChanged(&#160;)</B> depends
on the logic of your program.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_301">Add Comment</A></FONT><A NAME="_Toc534420125"></A><BR></P></DIV>
<A NAME="Heading76"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Observing flowers</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since Python doesn&#146;t have standard
library components to support the observer pattern (like Java does), we must
first create one. The simplest thing to do is translate the Java standard
library <B>Observer</B> and <B>Observable</B> classes. This also provides easier
translation from Java code that uses these libraries.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_302">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In trying to do this, we encounter a
minor snag, which is the fact that Java has a <B>synchronized</B> keyword that
provides built-in support for thread synchronization. We could certainly
accomplish the same thing by hand, using code like this:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_303">Add Comment</A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>import</font> threading 
<font color=#0000ff>class</font> ToSynch:
  <font color=#0000ff>def</font> __init__(self):
    self.mutex = threading.RLock()
    self.val = 1
  <font color=#0000ff>def</font> aSynchronizedMethod(self):
    self.mutex.acquire()
    <font color=#0000ff>try</font>:
      self.val += 1
      <font color=#0000ff>return</font> self.val
    <font color=#0000ff>finally</font>:
      self.mutex.release()</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">But this
rapidly becomes tedious to write and to read. Peter Norvig provided me with a
much nicer solution:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_304">Add Comment</A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>#: util:Synchronization.py
'''Simple emulation of Java's 'synchronized'
keyword, <font color=#0000ff>from</font> Peter Norvig.'''
<font color=#0000ff>import</font> threading

<font color=#0000ff>def</font> synchronized(method):
  <font color=#0000ff>def</font> f(*args):
    self = args[0]
    self.mutex.acquire();  
    # <font color=#0000ff>print</font> method.__name__, 'acquired'
    <font color=#0000ff>try</font>:
      <font color=#0000ff>return</font> apply(method, args)
    <font color=#0000ff>finally</font>:
      self.mutex.release();  
      # <font color=#0000ff>print</font> method.__name__, 'released'
  <font color=#0000ff>return</font> f

<font color=#0000ff>def</font> synchronize(klass, names=None):
  <font color=#004488>""</font>"Synchronize methods <font color=#0000ff>in</font> the given <font color=#0000ff>class</font>.  
  Only synchronize the methods whose names are 
  given, <font color=#0000ff>or</font> all methods <font color=#0000ff>if</font> names=None.<font color=#004488>""</font>"
  <font color=#0000ff>if</font> type(names)==type(''): names = names.split()
  <font color=#0000ff>for</font> (name, val) <font color=#0000ff>in</font> klass.__dict__.items():
    <font color=#0000ff>if</font> callable(val) <font color=#0000ff>and</font> name != '__init__' <font color=#0000ff>and</font> \
      (names == None <font color=#0000ff>or</font> name <font color=#0000ff>in</font> names):
        # <font color=#0000ff>print</font> <font color=#004488>"synchronizing"</font>, name
        klass.__dict__[name] = synchronized(val)

# You can create your own self.mutex, <font color=#0000ff>or</font> inherit
# <font color=#0000ff>from</font> this <font color=#0000ff>class</font>:
<font color=#0000ff>class</font> Synchronization:
  <font color=#0000ff>def</font> __init__(self):
    self.mutex = threading.RLock()
#:~</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>synchronized(&#160;)</B>
function takes a method and wraps it in a function that adds the mutex
functionality. The method is called inside this function:
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_305">Add Comment</A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>return</font> apply(method, args)</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">and
as the <B>return</B> statement passes through the <B>finally</B> clause, the
mutex is released.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_306">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is in some ways the <I>Decorator</I>
design pattern, but much simpler to create and use. All you have to say
is:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>myMethod = synchronized(myMethod)</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To
surround your method with a mutex.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_307">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>synchronize(&#160;)</B> is a
convenience function that applies <B>synchronized(&#160;)</B> to an entire
class, either all the methods in the class (the default) or selected methods
which are named in a string as the second argument.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_308">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Finally, for <B>synchronized( )</B> to
work there must be a <B>self.mutex</B> created in every class that uses
<B>synchronized( )</B>. This can be created by hand by the class author, but
it&#146;s more consistent to use inheritance, so the base class
<B>Synchronization</B> is provided.
<A HREF="http://www.mindview.net/Books/TIPython/BackTalk/FindPage/A_309">Add Comment</A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#146;s a simple test of the
<B>Synchronization</B> module.</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>#: util:TestSynchronization.py
<font color=#0000ff>from</font> Synchronization <font color=#0000ff>import</font> * 

# To use <font color=#0000ff>for</font> a method:
<font color=#0000ff>class</font> C(Synchronization):
  <font color=#0000ff>def</font> __init__(self):
    Synchronization.__init__(self)
    self.data = 1
  <font color=#0000ff>def</font> m(self):
    self.data += 1
    <font color=#0000ff>return</font> self.data
  m = synchronized(m)
  <font color=#0000ff>def</font> f(self): <font color=#0000ff>return</font> 47

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -