<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Chapter 16 Classes and functions 類和函數 Now that we know how to create new types, the next step is to write functions that take programmer-defined objects as parameters and return them as results. In this chapter I also present “functional programming style” and two new program development plans. > 現在我們已經知道如何創建新類型了,下一步就要寫一些函數了,這些函數用自定義類型做參數和返回值。在本章中還提供了一種函數式編程的模式,以及兩種新的程序開發規劃方式。 Code examples from this chapter are available from [Here](http://thinkpython2.com/code/Time1.py). Solutions to the exercises are at [Here](http://thinkpython2.com/code/Time1_soln.py). > 本章的樣例代碼可以在[這里](http://thinkpython2.com/code/Time1.py)下載。然后練習題的樣例代碼可以在[這里](http://thinkpython2.com/code/Time1_soln.py)下載到。 ## 16.1 Time 時間 As another example of a programmer-defined type, we’ll define a class called Time that records the time of day. The class definition looks like this: > 下面又是一個自定義類型的例子,這次咱們定義一個叫做 Time 的類,記錄下當日的時間。 > 類的定義是如下這樣: ```Python class Time: """Represents the time of day. attributes: hour, minute, second """ ``` We can create a new Time object and assign attributes for hours, minutes, and seconds: > 我們可以建立一個新的 Time 對象,然后對時分秒分別進行賦值: ```Python time = Time() time.hour = 11 time.minute = 59 time.second = 30 ``` The state diagram for the Time object looks like Figure 16.1. > 這個 Time 對象的狀態圖如圖16.1所示。 As an exercise, write a function called print_time that takes a Time object and prints it in the form hour:minute:second. Hint: the format sequence '%.2d' prints an integer using at least two digits, including a leading zero if necessary. > 下面做個練習,寫一個名為print_time 的函數,接收一個 Time 對象,然后以時:分:秒的格式來輸出。提示:格式序列'%.2d'就會用兩位來輸出一個整數,第一位可以為0。 Write a boolean function called is_after that takes two Time objects, t1 andt2, and returns True if t1 follows t2 chronologically and False otherwise. Challenge: don’t use an if statement. > 寫一個布爾函數,名為 is_after,接收兩個 Time 對象,分別為 t1和 t2,然后如果 t1在時間上位于 t2的后面,就返回真,否則返回假。難度提高一下:不要用 if 語句,看你能搞定不。 * * * ![Figure 16.1: Object diagram.](http://7xnq2o.com1.z0.glb.clouddn.com/ThinkPython16.1.png) Figure 16.1: Object diagram. * * * ## 16.2 Pure functions 純函數 In the next few sections, we’ll write two functions that add time values. They demonstrate two kinds of functions: pure functions and modifiers. They also demonstrate a development plan I’ll call prototype and patch, which is a way of tackling a complex problem by starting with a simple prototype and incrementally dealing with the complications. > 后面的這些章節中,我們要寫兩個函數來對 time 進行加法操作。這兩個函數展示了兩種函數類型:純函數和修改器。寫這兩個函數的過程中,也體現了我即將講到的一種新的開發模式:原型和補丁模式,這種方法就是在處理復雜問題的時候,先從簡單的原型開始,然后逐漸解決復雜的內容。 Here is a simple prototype of add_time: > 下面這段代碼就是 add_time 函數的一個原型: ```Python def add_time(t1, t2): sum = Time() sum.hour = t1.hour + t2.hour sum.minute = t1.minute + t2.minute sum.second = t1.second + t2.second return sum ``` The function creates a new Time object, initializes its attributes, and returns a reference to the new object. This is called a pure function because it does not modify any of the objects passed to it as arguments and it has no effect, like displaying a value or getting user input, other than returning a value. > 這個函數新建了一個新的 Time 對象,初始化了所有的值,然后返回了一個對新對象的引用。這種函數叫純函數,因為這種函數并不修改傳來做參數的對象,也沒有什么效果,比如顯示值啊或者讓用戶輸入啊等等,而只是返回一個值而已。 To test this function, I’ll create two Time objects: start contains the start time of a movie, like Monty Python and the Holy Grail, and duration contains the run time of the movie, which is one hour 35 minutes. add_time figures out when the movie will be done. > 下面就來測試一下這個函數,我將建立兩個 Time 對象,start 包含了一個電影的開始時間,比如《巨蟒與圣杯》(譯者注:1975年喜劇電影。Python的創造者Guido van Rossum特別喜歡這個喜劇團體:巨蟒飛行馬戲團(Monty Python’s Flying Circus ),所以命名為 Python。),然后 duration(漢譯就是持續時間)包含了該電影的時長,《巨蟒與圣杯》這部電影是一小時三十五分鐘。add_time 函數就會算出電影結束的時間。 ```Python >>> start = Time() >>> start = Time() >>> start.hour = 9 >>> start.hour = 9 >>> start.minute = 45 >>> start.minute = 45 >>> start.second = 0 >>> start.second = 0 >>> duration = Time() >>> duration = Time() >>> duration.hour = 1 >>> duration.hour = 1 >>> duration.minute = 35 >>> duration.minute = 35 >>> duration.second = 0 >>> duration.second = 0 >>> done = add_time(start, duration) >>> done = add_time(start, duration) >>> print_time(done) >>> print_time(done) 10:80:00 ``` The result, 10:80:00 might not be what you were hoping for. The problem is that this function does not deal with cases where the number of seconds or minutes adds up to more than sixty. When that happens, we have to “carry” the extra seconds into the minute column or the extra minutes into the hour column. Here’s an improved version: > 很明顯,10點80分00秒這樣的時間肯定不是你想要的結果。問題就出在了函數不值得如何應對時分秒的六十位進位,所以超過60的時候沒進位就這樣了。所以我們得把超出六十秒的進位到分,超過六十分的進位到小時。 > 下面這個是改進版本: ```Python def add_time(t1, t2): sum = Time() sum.hour = t1.hour + t2.hour sum.minute = t1.minute + t2.minute sum.second = t1.second + t2.second if sum.second >= 60: sum.second -= 60 sum.minute += 1 if sum.minute >= 60: sum.minute -= 60 sum.hour += 1 return sum ``` Although this function is correct, it is starting to get big. We will see a shorter alternative later. > 這回函數正確工作了,但代碼也開始變多了。稍后我們就能看到一個短一些的替代方案。 16.3 Modifiers 修改器 Sometimes it is useful for a function to modify the objects it gets as parameters. In that case, the changes are visible to the caller. Functions that work this way are called modifiers. > 有時候需要對作為參數的對象進行一些修改。這時候這些修改就可以被調用者察覺。這樣工作的函數就叫修改器了。 increment, which adds a given number of seconds to a Time object, can be written naturally as a modifier. Here is a rough draft: > increment 函數,增加給定的秒數到一個 Time 對象,就可以被改寫成一個修改器。 > 下面是個簡單的版本: ```Python def increment(time, seconds): time.second += seconds if time.second >= 60: time.second -= 60 time.minute += 1 if time.minute >= 60: time.minute -= 60 time.hour += 1 ``` The first line performs the basic operation; the remainder deals with the special cases we saw before. Is this function correct? What happens if seconds is much greater than sixty? > 第一行代碼進行了最簡單的運算;后面的代碼是用來應對我們之前討論過的特例情況。 > 那么這個函數正確么?秒數超過六十會怎么樣? In that case, it is not enough to carry once; we have to keep doing it until time.second is less than sixty. One solution is to replace the if statements with while statements. That would make the function correct, but not very efficient. > 很明顯,秒數超過六十的時候,就需要運行不只一次了;必須一直運行,之道 time.second 的值小于六十了才行。有一種辦法就是把 if 語句換成 while 語句。這樣就可以解決這個問題了,但效率不太高。 As an exercise, write a correct version of increment that doesn’t contain any loops. > 做個練習,寫一個正確的 increment 函數,并且要不包含任何循環。 Anything that can be done with modifiers can also be done with pure functions. In fact, some programming languages only allow pure functions. There is some evidence that programs that use pure functions are faster to develop and less error-prone than programs that use modifiers. But modifiers are convenient at times, and functional programs tend to be less efficient. > 能用修改器實現的功能也都能用純函數來實現。實際上有的編程語言只允許純函數。有證據表明,與修改器相比,使用修改器能夠更快地開發,而且不容易出錯誤。但修改器往往很方便好用,而函數式的程序一般效率要差一些。 In general, I recommend that you write pure functions whenever it is reasonable and resort to modifiers only if there is a compelling advantage. This approach might be called a functional programming style. > 總的來說,我還是建議你寫純函數,除非用修改器有特別顯著的好處。這種模式也叫做函數式編程。 As an exercise, write a “pure” version of increment that creates and returns a new Time object rather than modifying the parameter. > 做個練習,寫一個用純函數實現的 increment,創建并返回一個新的 Time 對象,而不是修改參數。 ## 16.4 Prototyping versus planning 原型與規劃 The development plan I am demonstrating is called “prototype and patch”. For each function, I wrote a prototype that performed the basic calculation and then tested it, patching errors along the way. > 這次我演示的開發規劃就是『原型與補丁模式』。對每個函數,我都先謝了一個簡單的原型,只進行基本的運算,然后測試一下,接下來逐步修補錯誤。 This approach can be effective, especially if you don’t yet have a deep understanding of the problem. But incremental corrections can generate code that is unnecessarily complicated—since it deals with many special cases—and unreliable—since it is hard to know if you have found all the errors. > 這種模式很有效率,尤其是在你對問題的理解不是很深入的時候。不過漸進式的修改也會產生過分復雜的代碼——因為要應對很多特例情況,而且也不太靠靠——因為不好確定你是否找到了所有的錯誤。 An alternative is designed development, in which high-level insight into the problem can make the programming much easier. In this case, the insight is that a Time object is really a three-digit number in base 60 (see [Here](http://en.wikipedia.org/wiki/Sexagesimal))! The second attribute is the “ones column”, the minute attribute is the “sixties column”, and the hour attribute is the “thirty-six hundreds column”. > 另一種模式就是設計規劃開發,這種情況下對問題的深入透徹的理解就讓開發容易很多了。本節中的根本性認識就在于 TIme 對象實際上是一個三位的六十進制數字(參考 [這里的解釋](http://en.wikipedia.org/wiki/Sexagesimal)。)!秒數也就是個位,分數也就是六十位,小時數就是三千六百位。 When we wrote add_time and increment, we were effectively doing addition in base 60, which is why we had to carry from one column to the next. > 這樣當我們寫 add_time 和 increment 函數的時候,用60進制來進行計算就很有效率。 This observation suggests another approach to the whole problem—we can convert Time objects to integers and take advantage of the fact that the computer knows how to do integer arithmetic. > 這一觀察表明有另外一種方法來解決整個問題——我們可以把 Time 對象轉換成整數,然后因為計算機最擅長整數運算,這樣就有優勢了。 Here is a function that converts Times to integers: > 下面這個函數就把 Times 轉換成了整數: ```Python def time_to_int(time): minutes = time.hour * 60 + time.minute seconds = minutes * 60 + time.second return seconds ``` And here is a function that converts an integer to a Time (recall that divmod divides the first argument by the second and returns the quotient and remainder as a tuple). > 然后下面這個函數是反過來的,把整數轉換成 Time(還記得 divmod 么,使用第一個數除以第二個數,返回的是除數和余數組成的元組。) ```Python def int_to_time(seconds): time = Time() minutes, time.second = divmod(seconds, 60) time.hour, time.minute = divmod(minutes, 60) return time ``` You might have to think a bit, and run some tests, to convince yourself that these functions are correct. One way to test them is to check that time_to_int(int_to_time(x)) == x for many values of x. This is an example of a consistency check. > 你最好先考慮好了,然后多進行幾次測試運行,然后要確保這些函數都是正確的。比如你就可以試著用很多個 x 的值來運算time_to_int(int_to_time(x)) == x。這也是連貫性檢測的一個例子。 Once you are convinced they are correct, you can use them to rewrite add_time: > 一旦你確定這些函數都沒問題,就可以用它們來重寫一下 add_time 這個函數了: ```Python def add_time(t1, t2): seconds = time_to_int(t1) + time_to_int(t2) return int_to_time(seconds) ``` This version is shorter than the original, and easier to verify. As an exercise, rewrite increment using time_to_int and int_to_time. > 這個版本就比最開始那個版本短多了,也更容易去檢驗了。接下來就做個聯系吧,用time_to_int 和 int_to_time 這兩個函數來重寫一下 increment。 In some ways, converting from base 60 to base 10 and back is harder than just dealing with times. Base conversion is more abstract; our intuition for dealing with time values is better. > 在一定程度上,從六十進制到十進制的來回轉換,遠遠比計算時間要麻煩的多。進制轉換要更加抽象很多;我們處理時間計算的直覺要更好些。 But if we have the insight to treat times as base 60 numbers and make the investment of writing the conversion functions (time_to_int and int_to_time), we get a program that is shorter, easier to read and debug, and more reliable. > 然而,如果我們有足夠的遠見,把時間值當做六十進制的數值來對待,然后寫出一些轉換函數(比如 time_to_int 和 int_to_time),就能讓程序變得更短,可讀性更好,調試更容易,也更加可靠。 It is also easier to add features later. For example, imagine subtracting two Times to find the duration between them. The naive approach would be to implement subtraction with borrowing. Using the conversion functions would be easier and more likely to be correct. > 而且后續添加功能也更容易了。比如,假設要對兩個時間對象進行相減來求二者之間的持續時間。簡單版本的方法就是要用借位的減法。而使用轉換函數的版本就更容易了,也更不容易出錯。 Ironically, sometimes making a problem harder (or more general) makes it easier (because there are fewer special cases and fewer opportunities for error). > 有意思的事,有時候以困難模式來寫一個程序(比如用更加泛化的模式),反而能讓開發更簡單(因為這樣就減少了特例情況,也減少了出錯誤的概率了。) ## 16.5 Debugging 調試 A Time object is well-formed if the values of minute and second are between 0 and 60 (including 0 but not 60) and if hour is positive. hour and minute should be integral values, but we might allow second to have a fraction part. > 對于一個 Time 對象來說,只要分和秒的值在0-60的前閉后開區間(即可以為0但不可以為60),并且小時數為正數,就是格式正確的。小時和分鐘都應該是整數,但秒是可以為小數的。 Requirements like these are called invariants because they should always be true. To put it a different way, if they are not true, something has gone wrong. > 像這些要求也叫約束條件,因為通常都得滿足這些條件才行。反過來說,如果這些條件沒滿足,就有可能是程序中某處存在錯誤了。 Writing code to check invariants can help detect errors and find their causes. For example, you might have a function like valid_time that takes a Time object and returns False if it violates an invariant: > 寫一些檢測約束條件的代碼,能夠幫助找出這些錯誤,并且找到導致錯誤的原因。例如,你虧寫一個名字未 calid_time 的函數,接收一個 Time 對象,然后如果該對象不滿足約束條件就返回 False: ```Python def valid_time(time): if time.hour < 0 or time.minute < 0 or time.second < 0: return False if time.minute >= 60 or time.second >= 60: return False return True ``` At the beginning of each function you could check the arguments to make sure they are valid: > 然后在每個自定義函數的開頭部位,你就可以檢測一下參數,來確保這些參數沒有錯誤: ```Python def add_time(t1, t2): if not valid_time(t1) or not valid_time(t2): raise ValueError('invalid Time object in add_time') seconds = time_to_int(t1) + time_to_int(t2) return int_to_time(seconds) ``` Or you could use an assert statement, which checks a given invariant and raises an exception if it fails: > 或者你也可以用一個 assert 語句,這個語句也是檢測給定的約束條件的,如果出現錯誤就會拋出一個異常: ```Python def add_time(t1, t2): assert valid_time(t1) and valid_time(t2) seconds = time_to_int(t1) + time_to_int(t2) return int_to_time(seconds) ``` assert statements are useful because they distinguish code that deals with normal conditions from code that checks for errors. > assert 語句是很有用的,可以用來區分條件語句的用途,將 assert 這種用于檢查錯誤的語句與常規的條件語句在代碼上進行區分。 ## 16.6 Glossary 術語列表 prototype and patch: A development plan that involves writing a rough draft of a program, testing, and correcting errors as they are found. > 原型和補丁模式:一種開發模式,先寫一個程序的草稿,然后測試,再改正發現的錯誤,這樣逐步演化的開發模式。 designed development: A development plan that involves high-level insight into the problem and more planning than incremental development or prototype development. > 設計規劃開發:這種開發模式要求對所面對問題的高程度的深刻理解,相比漸進式開發和原型增補模式要更具有計劃性。 pure function: A function that does not modify any of the objects it receives as arguments. Most pure functions are fruitful. > 純函數:不修改參數對象的函數。這種函數多數是有返回值的函數。 modifier: A function that changes one or more of the objects it receives as arguments. Most modifiers are void; that is, they return None. > 修改器:修改參數對象的函數。大多數這樣的函數都是無返回值的,也就是返回的都是 None。 functional programming style: A style of program design in which the majority of functions are pure. > 函數式編程模式:一種程序設計模式,主要特征為大多數函數都是純函數。 invariant: A condition that should always be true during the execution of a program. > 約束條件:在程序運行過程中,應該一直為真的條件。 assert statement: A statement that check a condition and raises an exception if it fails. > assert 語句:一種檢查錯誤的語句,檢查一個條件,如果不滿足就拋出異常。 ## 16.7 Exercises 練習 Code examples from this chapter are available from [Here](http://thinkpython2.com/code/Time1.py); solutions to the exercises are available from [Here](http://thinkpython2.com/code/Time1_soln.py). > 本章的例子可以在 [這里](http://thinkpython2.com/code/Time1.py)下載;練習題的答案可以在[這里](http://thinkpython2.com/code/Time1_soln.py)下載。 ### Exercise 1 練習1 Write a function called mul_time that takes a Time object and a number and returns a new Time object that contains the product of the original Time and the number. > 寫一個函數,名為mul_time,接收一個Time 對象和一個數值,返回一個二者相乘得到的新的Time 對象。 Then use mul_time to write a function that takes a Time object that represents the finishing time in a race, and a number that represents the distance, and returns a Time object that represents the average pace (time per mile). > 然后用 mul_time 這個函數寫一個函數,接收一個 Time 對象,代表著一個比賽的結束時間,還有一個數值,代表比賽距離,然后返回一個表示了平均步調(單位距離花費的時間)的新的 Time 對象。 ### Exercise 2 練習2 The datetime module provides time objects that are similar to the Time objects in this chapter, but they provide a rich set of methods and operators. Read the documentation at [Here](http://docs.python.org/3/library/datetime.html). > datetime 模塊提供了一些 time 對象,和本章的 Time 對象很相似,但前者提供了更多的方法和運算符。讀一讀[這里的文檔] [Here](http://docs.python.org/3/library/datetime.html)吧。 1. Use the datetime module to write a program that gets the current date and prints the day of the week. > 用 datetime 模塊來寫一個函數,獲取當前日期,然后輸出今天是星期幾。 2. Write a program that takes a birthday as input and prints the user’s age and the number of days, hours, minutes and seconds until their next birthday. > 寫一個函數,要求輸入生日,然后輸出用戶的年齡以及距離下一個生日的日、時、分、秒數。 3. For two people born on different days, there is a day when one is twice as old as the other. That’s their Double Day. Write a program that takes two birthdays and computes their Double Day. > 有的兩個人在不同日期出生,會在某一天,一個人的年齡是另外一個人年齡的兩杯。這一天就叫做他們的雙倍日。寫一個函數,接收兩個生日,然后計算雙倍日。 4. For a little more challenge, write the more general version that computes the day when one person is n times older than the other. > 再來點有挑戰性的,寫一個更通用的版本,來計算一下一個人的年齡為另外一個人年齡 n 倍時候的日期。 [Solution](http://thinkpython2.com/code/double.py). > [樣例代碼](http://thinkpython2.com/code/double.py)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看