<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Chapter 15 Classes and objects 類和對象 At this point you know how to use functions to organize code and built-in types to organize data. The next step is to learn “object-oriented programming”, which uses programmer-defined types to organize both code and data. Object-oriented programming is a big topic; it will take a few chapters to get there. Code examples from this chapter are available from [Here](http://thinkpython2.com/code/Point1.py); solutions to the exercises are available from [Here](http://thinkpython2.com/code/Point1_soln.py). > 到目前位置,你應該已經知道如何用函數來整理代碼,以及用內置類型來組織數據了。接下來的一步就是要學習『面向對象編程』了,這種編程方法中,用戶可以自定義類型來同時對代碼和數據進行整理。面向對象編程是一個很大的題目;要有好幾章才能講出個大概。 > 本章的樣例代碼可以在[這里](http://thinkpython2.com/code/Point1.py)來下載,練習題對應的樣例代碼可以在[這里](http://thinkpython2.com/code/Point1_soln.py)下載。 ## 15.1 Programmer-defined types 用戶自定義類型 We have used many of Python’s built-in types; now we are going to define a new type. As an example, we will create a type called Point that represents a point in two-dimensional space. > 我們已經用過很多 Python 的內置類型了;現在我們就要來定義一個新的類型了。作為樣例,我們會創建一個叫 Point 的類,用于表示一個二維空間中的點。 In mathematical notation, points are often written in parentheses with a comma separating the coordinates. For example, (0,0) represents the origin, and (x,y) represents the point x units to the right and y units up from the origin. > 數學符號上對點的表述一般是一個括號內有兩個坐標,坐標用逗號分隔開。比如,(0,0)就表示為原點,(x,y)就表示了該點從原點向右偏移 x,向上偏移 y。 There are several ways we might represent points in Python: > 我們可以用好幾種方法來在 Python 中表示一個點: ? We could store the coordinates separately in two variables, x and y. > 我們可以把坐標存儲成兩個單獨的值,x 和 y。 ? We could store the coordinates as elements in a list or tuple. > 還可以把坐標存儲成列表或者元組的元素。 ? We could create a new type to represent points as objects. > 還可以創建一個新的類型來用對象表示點。 Creating a new type is more complicated than the other options, but it has advantages that will be apparent soon. > 創建新的類型要比其他方法更復雜一點,不過也有一些優勢,等會我們就會發現了。 A programmer-defined type is also called a class. A class definition looks like this: > 用戶自定義的類型也被叫做一個類。一個類的定義大概是如下所示的樣子: ```Python class Point: """Represents a point in 2-D space.""" ``` The header indicates that the new class is called Point. The body is a docstring that explains what the class is for. You can define variables and methods inside a class definition, but we will get back to that later. > 頭部代碼的意思是表示新建的類名字叫 Point。然后類的體內有一個文檔字符串,解釋類的用途。在類的定義內部可以定義各種變量和方法,等會再來詳細學習一下這些內容哈。 Defining a class named Point creates a class object. > 聲明一個名為 Point 的類,就可以創建該類的一個對象。 ```Python >>> Point >>> Point <class '__main__.Point'> ``` Because Point is defined at the top level, its “full name” is \_\_main\_\_.Point. > 因為 Point 是在頂層位置定義的,所以全名就是\_\_main\_\_.Point。 The class object is like a factory for creating objects. To create a Point, you call Point as if it were a function. > 類的對象就像是一個創建對象的工廠。要創建一個 Point,就可以像調用函數一樣調用 Point。 ```Python >>> blank = Point() >>> blank = Point() >>> blank >>> blank <__main__.Point object at 0xb7e9d3ac> ``` The return value is a reference to a Point object, which we assign to blank. Creating a new object is called instantiation, and the object is an instance of the class. > 返回值是到一個 Point 對象的引用,剛剛賦值為空白了。 > 創建一個新的對象也叫做實例化,這個對象就是類的一個實例。 When you print an instance, Python tells you what class it belongs to and where it is stored in memory (the prefix 0x means that the following number is in hexadecimal). > 用 Print 輸出一個實例的時候,Python 會告訴你該實例所屬的類,以及在內存中存儲的位置(前綴為0x 意味著下面的這些數值是十六進制的。) Every object is an instance of some class, so “object” and “instance” are interchangeable. But in this chapter I use “instance” to indicate that I am talking about a programmer-defined type. > 每一個對象都是某一個類的一個實例,所以『對象』和『實例』可以互換來使用。不過本章我還是都使用『實例』這個詞,這樣就更能體現出咱們在談論的是用戶定義的類型。 ## 15.2 Attributes 屬性 You can assign values to an instance using dot notation: > 用點號可以給實例進行賦值: ```Python >>> blank.x = 3.0 >>> blank.x = 3.0 >>> blank.y = 4.0 >>> blank.y = 4.0 ``` This syntax is similar to the syntax for selecting a variable from a module, such as math.pi or string.whitespace. In this case, though, we are assigning values to named elements of an object. These elements are called attributes. > 這一語法形式就和從模塊中選取變量的語法是相似的,比如 math.pi 或者 string.whitespace。然而在本章這種情況下,我們用點號實現的是對一個對象中某些特定名稱的元素進行賦值。這些元素也叫做屬性。 As a noun, “AT-trib-ute” is pronounced with emphasis on the first syllable, as opposed to “a-TRIB-ute”, which is a verb. > 『Attribute』作為名詞的發音要把重音放在第一個音節,而做動詞的時候是重音放到第二音節。 The following diagram shows the result of these assignments. A state diagram that shows an object and its attributes is called an object diagram; see Figure 15.1. > 下面的圖表展示了上面這些賦值的結果。用于展示一個類及其屬性的狀態圖也叫做類圖;比如圖15.1就是一例。 * * * ![Figure 15.1: Object diagram](http://7xnq2o.com1.z0.glb.clouddn.com/ThinkPython15.1.png) Figure 15.1: Object diagram. * * * The variable blank refers to a Point object, which contains two attributes. Each attribute refers to a floating-point number. > 變量 blank 指代的是一個 Point 對象,該對象包含兩個屬性。每個屬性都指代了一個浮點數。 You can read the value of an attribute using the same syntax: > 讀取屬性值可以用如下這樣的語法: ```Python >>> blank.y >>> blank.y 4.0 >>> x = blank.x >>> x = blank.x >>> x >>> x 3.0 ``` The expression blank.x means, “Go to the object blank refers to and get the value of x.” In the example, we assign that value to a variable named x. There is no conflict between the variable x and the attribute x. > 這里的表達式 blank.x 的意思是,『到 blank 所指代的對象中,讀取 x 的值。』在這個例子中,我們把這個值賦值給一個名為 x 的變量。這里的變量 x 和類的屬性x 并不沖突。 You can use dot notation as part of any expression. For example: > 點號可以隨意在任意表達式中使用。比如下面這個例子: ```Python >>> '(%g, %g)' % (blank.x, blank.y) >>> '(%g, %g)' % (blank.x, blank.y) '(3.0, 4.0)' >>> distance = math.sqrt(blank.x**2 + blank.y**2) >>> distance = math.sqrt(blank.x**2 + blank.y**2) >>> distance >>> distance 5.0 ``` You can pass an instance as an argument in the usual way. For example: > 你還可以把實例作為一個參數來使用。比如下面這樣: ```Python def print_point(p): print('(%g, %g)' % (p.x, p.y)) ``` print_point takes a point as an argument and displays it in mathematical notation. To invoke it, you can pass blank as an argument: > print_point 這個函數就接收了一個點作為參數,然后顯示點的數值位置。你可以把剛剛那個 blank 作為參數傳過去來試試: ```Python >>> print_point(blank) >>> print_point(blank) (3.0, 4.0) ``` Inside the function, p is an alias for blank, so if the function modifies p, blank changes. > 在函數內部,p 是blank 的一個別名,所以如果函數內部對 p 進行了修改,blank 也會發生相應的改變。 As an exercise, write a function called distance_between_points that takes two Points as arguments and returns the distance between them. > 做個練習,寫一個名為 distance_between_points 的函數,接收兩個點作為參數,然后返回兩點之間的距離。 ## 15.3 Rectangles 矩形 Sometimes it is obvious what the attributes of an object should be, but other times you have to make decisions. For example, imagine you are designing a class to represent rectangles. What attributes would you use to specify the location and size of a rectangle? You can ignore angle; to keep things simple, assume that the rectangle is either vertical or horizontal. > 有時候一個類中的屬性應該如何設置是很明顯的,不過有的時候就得好好考慮一下了。比如,假設你要設計一個表示矩形的類。你要用什么樣的屬性來確定一個矩形的位置和大小呢?可以忽略角度;來讓情況更簡單一些,就只考慮矩形是橫向的或者縱向的。 There are at least two possibilities: > 至少有兩種方案備選: ? You could specify one corner of the rectangle (or the center), the width, and the height. > 確定矩形的一個頂點(或者中心)所在位置,還有寬度和高度。 ? You could specify two opposing corners. > 確定對角線上的兩個頂點所在位置。 At this point it is hard to say whether either is better than the other, so we’ll implement the first one, just as an example. > 現在還很難說這兩者哪一個更好,那么咱們先用第一個方案來做個例子。 Here is the class definition: > 下面就是類的定義: ```Python class Rectangle: """Represents a rectangle. attributes: width, height, corner. """ ``` The docstring lists the attributes: width and height are numbers; corner is a Point object that specifies the lower-left corner. > 文檔字符串中列出了屬性:width 和 height 是數值;corner 是一個點對象,用來表示左下角頂點。 To represent a rectangle, you have to instantiate a Rectangle object and assign values to the attributes: > 要表示一個矩形,必須初始化一個矩形對象,然后對其屬性進行賦值: ```Python box = Rectangle() box.width = 100.0 box.height = 200.0 box.corner = Point() box.corner.x = 0.0 box.corner.y = 0.0 ``` The expression box.corner.x means, “Go to the object box refers to and select the attribute named corner; then go to that object and select the attribute named x.” > 表達式 box.corner.x 的意思是,『到 box 指代的對象中,選擇名為 corner 的屬性;然后到這個點對象中,選取名為 x 的屬性值。』 * * * ![Figure 15.2: Object diagram](http://7xnq2o.com1.z0.glb.clouddn.com/ThinkPython15.2.png) Figure 15.2: Object diagram. * * * Figure 15.2 shows the state of this object. An object that is an attribute of another object is embedded. > 圖15.2展示了這個對象的狀態圖。一個類去作為另外一個類的屬性,就叫做嵌入。 ## 15.4 Instances as return values 多個實例作返回值 Functions can return instances. For example, find_center takes a Rectangle as an argument and returns a Point that contains the coordinates of the center of the Rectangle: > 函數虧返回實例。比如 find_center 就接收一個 Rectangle (矩陣)對象作為參數,然后以一個Point(點)對象的形式返回矩形中心位置的坐標所在點: ```Python def find_center(rect): p = Point() p.x = rect.corner.x + rect.width/2 p.y = rect.corner.y + rect.height/2 return p ``` Here is an example that passes box as an argument and assigns the resulting Point to center: > 下面這個例子中,box 作為一個參數傳遞給了 find_center 函數,然后結果賦值給了點 center: ```Python >>> center = find_center(box) >>> center = find_center(box) >>> print_point(center) >>> print_point(center) (50, 100) ``` ## 15.5 Objects are mutable 對象可以修改 You can change the state of an object by making an assignment to one of its attributes. For example, to change the size of a rectangle without changing its position, you can modify the values of width and height: > 通過對一個對象的屬性進行賦值就可以修改該對象的狀態了。比如,要改變一個舉行的大小而不改變位置,就可以只修改寬度和高度,如下所示: ```Python box.width = box.width + 50 box.height = box.height + 100 ``` You can also write functions that modify objects. For example, grow_rectangle takes a Rectangle object and two numbers, dwidth and dheight, and adds the numbers to the width and height of the rectangle: > 你還可以寫專門的函數來修改對象。比如grow_rectangle這個函數就接收一個矩形對象和dwidth 與 dheight兩個數值,然后把這兩個數值加到矩形的寬度和高度值上。 ```Python def grow_rectangle(rect, dwidth, dheight): rect.width += dwidth rect.height += dheight ``` Here is an example that demonstrates the effect: > 下面的例子展示了具體的效果: ```Python >>> box.width, box.height >>> box.width, box.height (150.0, 300.0) >>> grow_rectangle(box, 50, 100) >>> grow_rectangle(box, 50, 100) >>> box.width, box.height >>> box.width, box.height (200.0, 400.0) ``` Inside the function, rect is an alias for box, so when the function modifies rect,box changes. > 在函數的內部,rect 是 box 的一個別名,所以當函數修改了 rect 的時候,box 就得到了相應的修改。 As an exercise, write a function named move_rectangle that takes a Rectangle and two numbers named dx and dy. It should change the location of the rectangle by adding dx to the x coordinate of corner and adding dy to the y coordinate of corner. > 做個練習,寫一個名為 move_rectangle 的函數,接收一個矩形和dx 與 dy 兩個數值。函數要改變矩形所在位置,具體的改變方法為對左下角頂點坐標的 x 和 y 分別加上 dx 和 dy 的值。 ## 15.6 Copying 復制 Aliasing can make a program difficult to read because changes in one place might have unexpected effects in another place. It is hard to keep track of all the variables that might refer to a given object. > 別名有可能讓程序讀起來有困難,因為在一個位置做出的修改有可能導致另外一個位置發生不可預知的情況。這樣也很難去追蹤指向一個對象的所有變量。 Copying an object is often an alternative to aliasing. The copy module contains a function called copy that can duplicate any object: > 所以就可以不用別名,而用復制對象的方法。copy 模塊包含了一個名叫 copy 的函數,可以復制任意對象: ```Python >>> p1 = Point() >>> p1 = Point() >>> p1.x = 3.0 >>> p1.x = 3.0 >>> p1.y = 4.0 >>> p1.y = 4.0 >>> import copy >>> import copy >>> p2 = copy.copy(p1) >>> p2 = copy.copy(p1) ``` p1 and p2 contain the same data, but they are not the same Point. > p1和 p2包含的數據是相同的,但并不是同一個點對象。 ```Python >>> print_point(p1) >>> print_point(p1) (3, 4) >>> print_point(p2) >>> print_point(p2) (3, 4) >>> p1 is p2 >>> p1 is p2 False >>> p1 == p2 >>> p1 == p2 False ``` The is operator indicates that p1 and p2 are not the same object, which is what we expected. But you might have expected == to yield True because these points contain the same data. In that case, you will be disappointed to learn that for instances, the default behavior of the == operator is the same as the is operator; it checks object identity, not object equivalence. That’s because for programmer-defined types, Python doesn’t know what should be considered equivalent. At least, not yet. > is 運算符表明 p1和 p2不是同一個對象,這就是我們所預料的。但你可能本想著是==運算符應該得到的是 True 因為這兩個點包含的數據是一樣的。這樣的話你就會很失望地發現對于實例來說,==運算符的默認行為就跟 is 運算符是一樣的;它也還是檢查對象的身份,而不是對象的相等性。這是因為你用的是用戶自定義的類型,Python 不值得如何去衡量是否相等。至少是現在還不能。 > (譯者注:==運算符的實現需要運算符重載,也就是多態的一種,來實現,也就是對用戶自定義類型,需要用戶自定義運算符,而不能簡單地繼續用內置運算符。因為自定義類型的運算是 Python 沒法確定的,得用戶自己來確定。) If you use copy.copy to duplicate a Rectangle, you will find that it copies the Rectangle object but not the embedded Point. > 如果你用 copy.copy 復制了一個矩形,你會發現該函數復制了矩形對象,但沒有復制內嵌的點對象。 ```Python >>> box2 = copy.copy(box) >>> box2 = copy.copy(box) >>> box2 is box >>> box2 is box False >>> box2.corner is box.corner >>> box2.corner is box.corner True ``` * * * ![Figure 15.3: Object diagram](http://7xnq2o.com1.z0.glb.clouddn.com/ThinkPython15.3.png) Figure 15.3: Object diagram. * * * Figure 15.3 shows what the object diagram looks like. This operation is called a shallow copy because it copies the object and any references it contains, but not the embedded objects. > 圖15.3展示了此時的類圖的情況。這種運算叫做淺復制,因為復制了對象與對象內包含的所有引用,但不復制內嵌的對象。 For most applications, this is not what you want. In this example, invoking grow_rectangle on one of the Rectangles would not affect the other, but invoking move_rectangle on either would affect both! This behavior is confusing and error-prone. > 對于大多數應用來說,這并不是你的本來目的。在本節的樣例中,對復制過的一個矩形進行 grow_rrectangle 函數運算,并不會影響另外一個,但使用 move_rectangle 就會對兩個都有影響!這種行為就很讓人疑惑,也容易帶來錯誤。 Fortunately, the copy module provides a method named deepcopy that copies not only the object but also the objects it refers to, and the objects they refer to, and so on. You will not be surprised to learn that this operation is called a deep copy. > 所幸的是 copy 模塊還提供了一個名為 deepcopy (深復制)的方法,這樣就能把內嵌的對象也復制了。你肯定不會奇怪了,這種運算就叫深復制了。 ```Python >>> box3 = copy.deepcopy(box) >>> box3 = copy.deepcopy(box) >>> box3 is box >>> box3 is box False >>> box3.corner is box.corner >>> box3.corner is box.corner False ``` box3 and box are completely separate objects. As an exercise, write a version of move_rectangle that creates and returns a new Rectangle instead of modifying the old one. > box3和 box 就是完全隔絕開,沒有公用內嵌對象,徹底不會相互干擾的兩個對象了。 > 做個聯系吧,寫一個新版本的 move_rectangle,創建并返回一個新的矩形,而不是修改舊有的矩形。 ## 15.7 Debugging 調試 When you start working with objects, you are likely to encounter some new exceptions. If you try to access an attribute that doesn’t exist, you get an AttributeError: > 當你開始使用對象的時候,你就容易遇到一些新的異常。如果你試圖讀取一個不存在的屬性,就會得到一個屬性錯誤AttributeError: ```Python >>> p = Point() >>> p = Point() >>> p.x = 3 >>> p.x = 3 >>> p.y = 4 >>> p.y = 4 >>> p.z >>> p.z AttributeError: Point instance has no attribute 'z' ``` If you are not sure what type an object is, you can ask: > 如果不確定一個對象是什么類型,可以『問』一下: ```Python >>> type(p) >>> type(p) <class '__main__.Point'> ``` You can also use isinstance to check whether an object is an instance of a class: > 還可以用 isinstance 函數來檢查一下一個對象是否為某一個類的實例: ```Python >>> isinstance(p, Point) >>> isinstance(p, Point) True ``` If you are not sure whether an object has a particular attribute, you can use the built-in function hasattr: > 如果不確定某一對象是否有一個特定的屬性,可以用內置函數 hasattr: ```Python >>> hasattr(p, 'x') >>> hasattr(p, 'x') True >>> hasattr(p, 'z') >>> hasattr(p, 'z') False ``` The first argument can be any object; the second argument is a string that contains the name of the attribute. > hasattr 的第一個參數可以是任意一個對象;第二個參數是一個字符串,就是要判斷是否存在的屬性名字。 You can also use a try statement to see if the object has the attributes you need: > 用 try 語句也可以試驗一個對象是否有你需要的屬性: ```language try: x = p.x except AttributeError: x = 0 ``` This approach can make it easier to write functions that work with different types; more on that topic is coming up in Section 17.9. > 這樣寫一些處理不同類型變量的函數就更容易了;關于這一話題的更多內容會在17.9中展開。 ## 15.8 Glossary 術語列表 class: A programmer-defined type. A class definition creates a new class object. > 類:用戶定義的類型。一個類的聲明建立了一個新的類的對象。 class object: An object that contains information about a programmer-defined type. The class object can be used to create instances of the type. > 類的對象:包含了用戶自定義類型相關信息的一個對象。可以用于創建類的一個實例。 instance: An object that belongs to a class. > 實例:術語某一個類的一個對象。 instantiate: To create a new object. > 實例化:創建一個新的對象。 attribute: One of the named values associated with an object. > 屬性:一個對象內附屬的數值的名字。 embedded object: An object that is stored as an attribute of another object. > 內嵌對象:一個對象作為屬性存儲在另一個對象內。 shallow copy: To copy the contents of an object, including any references to embedded objects; implemented by the copy function in the copy module. > 淺復制:復制一個對象中除了內嵌對象之外的所有引用;通過 copy 模塊的 copy 函數來實現。 deep copy: To copy the contents of an object as well as any embedded objects, and any objects embedded in them, and so on; implemented by the deepcopy function in the copy module. > 深復制:復制一個對象的所有內容,包括內嵌對象,以及內嵌對象中的所有內嵌對象等等;通過 copy 模塊的 deepcopy 函數來實現。 object diagram: A diagram that shows objects, their attributes, and the values of the attributes. > 類圖:一種圖解,用于展示類與類中的屬性以及屬性的值。 ## 15.9 Exercises 練習 ### Exercise 1 練習1 Write a definition for a class named Circle with attributes center and radius, where center is a Point object and radius is a number. > 寫一個名為 Circle 的類的定義,屬性為圓心center和半徑radius,center 是一個點對象,半徑是一個數值。 Instantiate a Circle object that represents a circle with its center at (150, 100) and radius 75. > 實例化一個 Circle 的對象,表示一個圓,圓心在(150,100),半徑為75。 Write a function named point_in_circle that takes a Circle and a Point and returns True if the Point lies in or on the boundary of the circle. > 寫一個名為 point_in_circle 的函數,接收一個 Circle 和一個 Point 對象作為參數,如果點在圓內或者圓的線上就返回True。 Write a function named rect_in_circle that takes a Circle and a Rectangle and returns True if the Rectangle lies entirely in or on the boundary of the circle. > 寫一個名為 rect_in_circle 的函數,接收一個 Circle 和一個 Rectangle 對象作為參數,如果矩形的邊都內含或者內切在圓內,就返回 True。 Write a function named rect_circle_overlap that takes a Circle and a Rectangle and returns True if any of the corners of the Rectangle fall inside the circle. Or as a more challenging version, return True if any part of the Rectangle falls inside the circle. > 寫一個名為 rect_circle_overlap 的函數,接收一個 Circle 和一個 Rectangle 對象作為參數,如果矩形任意一個頂點在圓內就返回 True。或者寫個更有挑戰性的版本,如果矩形有任意部分包含在圓內就返回 True。 [Solution](http://thinkpython2.com/code/Circle.py). > [樣例代碼](http://thinkpython2.com/code/Circle.py)。 ### Exercise 2 練習2 Write a function called draw_rect that takes a Turtle object and a Rectangle and uses the Turtle to draw the Rectangle. See Chapter 4 for examples using Turtle objects. > 寫一個名為 draw_rect的函數,接收一個 Turtle 對象和一個 Rectangle 對象作為參數,用 Turtle 畫出這個矩形。可以參考一下第四章對 Turtle 對象使用的樣例。 Write a function called draw_circle that takes a Turtle and a Circle and draws the Circle. [Solution](http://thinkpython2.com/code/draw.py). > 寫一個名為 draw_circle 的函數,接收一個 Turtle 對象和一個 Circle 對象,畫個圓這次。 > [樣例代碼](http://thinkpython2.com/code/draw.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>

                              哎呀哎呀视频在线观看