[譯]Python提高:Python類和面向對象編程

原文作者:Jeff Knupp

原文鏈接:這里

<font color=red>class</font>是Python的基礎構建快。它是很多流行的程序和庫,以及Python標準庫的基礎依托。理解類是什么,什么時候使用,以及它們如何有用至關重要,這也是本文的目的。在這個過程中,我們會探討“面向對象編程”的含義,以及它與Python類之間的聯系。

一切都是對象...

<font color=red>class</font>關鍵字究竟是什么?跟它基于函數的<font color=red>def</font>表兄弟類似,它用于定義事物。<font color=red>def</font>用來定義函數,<font color=red>class</font>用來定義。什么是類?就是一個數據和函數(在類中定義時,通常叫做“方法”)的邏輯分組。

“邏輯分組”是什么意思?一個類可以包含我們希望的任何數據和函數(方法)。我們嘗試創建事物之間有邏輯聯系的類,而不是把隨機的事物放在“類”名下面。很多時候,類都是基于真實世界的物體(比如<font color=red>Customer</font>和<font color=red>Product</font>)。其它時候,類基于系統中的概念,比如<font color=red>HTTPRequest</font>和<font color=red>Owner</font>。

不管怎么樣,類是一種建模技術,一種思考程序的方式。當你用這種方式思考和實現你的系統時,被稱為使用面向對象編程。“類”和“對象”經常互換使用,但實際上它們并不相同。理解它們是什么和它們是如何工作的關鍵是理解它們之間的區別。

..所以一切都有一個類?

類可以看做是創建對象的藍圖。當我使用<font color=red>class</font>關鍵字定義一個Customer類時,我并沒有真正創建一個顧客。相反,我創建的是構建顧客對象的說明手冊。讓我們看以下示例代碼:

class Customer(object):
    """A customer of ABC Bank with a checking account. Customers have the
    following properties:

    Attributes:
        name: A string representing the customer's name.
        balance: A float tracking the current balance of the customer's account.
    """

    def __init__(self, name, balance=0.0):
        """Return a Customer object whose name is *name* and starting
        balance is *balance*."""
        self.name = name
        self.balance = balance

    def withdraw(self, amount):
        """Return the balance remaining after withdrawing *amount*
        dollars."""
        if amount > self.balance:
            raise RuntimeError('Amount greater than available balance.')
        self.balance -= amount
        return self.balance

    def deposit(self, amount):
        """Return the balance remaining after depositing *amount*
        dollars."""
        self.balance += amount
        return self.balance

<font color=red>class Customer(object)</font>并沒有創建一個新的顧客。我們只是定義了一個<font color=red>Customer</font>,并不意味著創建了一個顧客;我們僅僅勾勒出創建<font color=red>Customer</font>對象的藍圖。用正確的參數數量(去掉<font color=red>self</font>,我們馬上會討論)調用類的<font color=red>__init__</font>方法可以創建一個顧客。

因此,要使用通過<font color=red>class Customer</font>(用于創建<font color=red>Customer</font>對象)定義的“藍圖”,可以把類名看做一個函數來調用:<font color=red>jeff = Customer('Jeff Knupp', 1000.0)</font>。這行代碼表示:使用<font color=red>Customer</font>藍圖創建一個新對象,并把它指向<font color=red>jeff</font>。

被稱為實例的<font color=red>jeff</font>對象是<font color=red>Customer</font>的實現版本。我們調用<font color=red>Customer()</font>之前,不存在<font color=red>Customer</font>對象。當然,我們可以創建任意多個<font color=red>Customer</font>對象。但是不管我們創建多少<font color=red>Customer</font>實例,仍然只有一個<font color=red>Customer</font>

<font color=red>self</font>?

對應所有<font color=red>Customer</font>方法來說,<font color=red>self</font>參數是什么?當然,它是實例。換一種方式,像<font color=red>withdraw</font>這樣的方法,定義了從某些抽象顧客的賬戶中取錢的指令。調用<font color=red>jeff.withdraw(1000.0)</font>把這些指令用在<font color=red>jeff</font>實例上。

所以,當我們說:<font color=red>def withdraw(self, amount):</font>,我們的意思是:這是你如何從一個顧客對象(我們稱為<font color=red>self</font>)和一個美元數字(我們稱為<font color=red>amount</font>)取錢。<font color=red>self</font>是<font color=red>Customer</font>的實例,在它上面調用<font color=red>withdraw</font>。這也不是我做類比。<font color=red>jeff.withdraw(1000.0)</font>只是<font color=red>Customer.withdraw(jeff, 1000.0)</font>的簡寫,也是完全有限的代碼。

<font color=red>__init__</font>

<font color=red>self</font>可能對其它方法也有意義,但是<font color=red>__init__</font>呢?當我們調用<font color=red>__init__</font>時,我們在創建一個對象的過程中,為什么已經有了<font color=red>self</font>?盡管不完全適合,Python還是允許我們擴展<font color=red>self</font>模式到對象的構造。想象<font color=red>jeff = Customer('Jeff Knupp', 1000.0)</font>等價于<font color=red>jeff = Customer(jeff, 'Jeff Knupp', 1000.0)</font>;傳入的<font color=red>jeff</font>也是同樣的結果。

這就是為什么調用<font color=red>__init__</font>時,我們通過<font color=red>self.name = name</font>來初始化對象。記住,因為<font color=red>self</font>是實例,所以它等價于<font color=red>jeff.name = name</font>,它等價于<font color=red>jeff.name = 'Jeff Knupp'</font>。同樣的,<font color=red>self.balance = balance</font>等價于<font color=red>jeff.balance = 1000.0</font>。這兩行代碼之后,我們認為<font color=red>Customer</font>對象已經“初始化”,可以被使用。

完成<font color=red>__init__</font>后,調用者可以假設對象已經可以使用。也就是,調用<font color=red>jeff = Customer('Jeff Knupp', 1000.0)</font>后,我們可以在<font color=red>jeff</font>上調用<font color=red>deposit</font>和<font color=red>withdraw</font>;<font color=red>jeff</font>是一個完全初始化的對象。

我們定義了另外一個稍微不同的<font color=red>Customer</font>類:

class Customer(object):
    """A customer of ABC Bank with a checking account. Customers have the
    following properties:

    Attributes:
        name: A string representing the customer's name.
        balance: A float tracking the current balance of the customer's account.
    """

    def __init__(self, name):
        """Return a Customer object whose name is *name*.""" 
        self.name = name

    def set_balance(self, balance=0.0):
        """Set the customer's starting balance."""
        self.balance = balance

    def withdraw(self, amount):
        """Return the balance remaining after withdrawing *amount*
        dollars."""
        if amount > self.balance:
            raise RuntimeError('Amount greater than available balance.')
        self.balance -= amount
        return self.balance

    def deposit(self, amount):
        """Return the balance remaining after depositing *amount*
        dollars."""
        self.balance += amount
        return self.balance

它看起來是一個合理的替代者;在使用實例之前,只需要簡單的調用<font color=red>set_balance</font>。但是,沒有一種方式可以告訴調用者這么做。即使我們在文檔中說明了,也不能強制調用者在調用<font color=red>jeff.withdraw(100.0)</font>之前調用<font color=red>jeff.set_balance(1000.0)</font>。<font color=red>jeff</font>實例在調用<font color=red>jeff.set_balance</font>之前沒有<font color=red>balance</font>屬性,這意味著對象沒有“完全”初始化。

簡單來說,不要在<font color=red>__init__</font>方法之外引入新的屬性,否則你會給調用一個沒有完全初始化的對象。當然也有例外,但這是一個需要記住的原則。這是對象一致性這個大概念的一部分:不應該有任何一系列的方法調用可能導致對象進入沒有意義的狀態。

不變性(比如“賬戶余額總是非負數”)應該在方法進入和退出時都保留。對象不可能通過調用它的方法進入無效狀態。不用說,一個對象也應該從一個有效的狀態開始,這就是為什么在<font color=red>__init__</font>方法中初始化所有內容是很重要的。

實例屬性和方法

定義在類中的函數稱為“方法”。方法可以訪問包含在對象實例中的所有數據;它們可以訪問和修改之前在<font color=red>self</font>上設置的任何內容。因為它們使用<font color=red>self</font>,所以需要使用類的一個實例。基于這個原因,它們通常被稱為“實例方法”。

如果有“實例方法”,一定也會有其它類型的方法,對吧?是的,確實有,但這些方法有些深奧。我們會在這里簡略的介紹一下,但是可以更深入的研究這些主題。

靜態方法

類屬性是在類級別上設置的屬性,相對的是實例級別。普通屬性在<font color=red>__init__</font>方法中引入,但有些屬性適用于所有實例。例如,思考下面<font color=red>Car</font>對象的定義:

class Car(object):

    wheels = 4

    def __init__(self, make, model):
        self.make = make
        self.model = model

mustang = Car('Ford', 'Mustang')
print mustang.wheels
# 4
print Car.wheels
# 4

不管<font color=red>make</font>和<font color=red>model</font>是什么,一輛<font color=red>Car</font>總是有四個<font color=red>Wheels</font>。實例方法可以通過跟訪問普通屬性一樣訪問這些屬性:通過<font color=red>self</font>(比如,<font color=red>self.wheels</font>)。

有一種稱為靜態方法的方法,它們不能訪問<font color=red>self</font>。跟類屬性類似,它們不需要實例就能工作。因為實例總是通過<font color=red>self</font>引用,所以靜態方法沒有<font color=red>self</font>參數。

下面是<font color=red>Car</font>類的一個有效的靜態方法:

class Car(object):
    ...
    def make_car_sound():
        print 'VRooooommmm!'

不管我們擁有什么類型的汽車,它總是發出相同的聲音。為了說明這個方法不應該接收實例作為第一個參數(比如“普通”方法的<font color=red>self</font>),可以使用<font color=red>@staticmethod</font>裝飾器,把我們的定義變成:

class Car(object):
    ...
    @staticmethod
    def make_car_sound():
        print 'VRooooommmm!'

類方法

靜態方法的一個變種是類方法。它傳遞,而不是實例作為第一個參數。它也使用裝飾器定義:

class Vehicle(object):
    ...
    @classmethod
    def is_motorcycle(cls):
        return cls.wheels == 2

現在類方法可能沒有太大的意義,但它通常與下一個主題聯系在一起:繼承

繼承

面向對象編程作為建模工具非常有用,引入繼承的概念后,它真正變強大了。

繼承是“子”類衍生“父”類的數據和行為的過程。有一個實例可以明確的幫助我們理解。

想象我們經營了一家汽車銷售店。我們銷售所有類型的車輛,從摩托車到卡車。我們通過價格與競爭對手區分開來。特別是我們如何確定車輛的價格:$5000 * 一臺車輛擁有的車輪數。我們也喜歡回購車輛。我們提供統一的價格 - 車輛行駛里程的10%。卡車的價格是$10,000,汽車是$8,000,摩托車是$4,000。

如果我們想用面對對象技術為汽車銷售店創建一個銷售系統,應該怎么做?對象是什么?我們可能有一個<font color=red>Sale</font>類,一個<font color=red>Customer</font>類,一個<font color=red>Inventor</font>類等等,但我們肯定有一個<font color=red>Car</font>,<font color=red>Truck</font>和<font color=red>Motorcycle</font>類。

這些類應該是什么樣的?用我們已經學會的知識,以下是<font color=red>Car</font>類的一種實現:

class Car(object):
    """A car for sale by Jeffco Car Dealership.

    Attributes:
        wheels: An integer representing the number of wheels the car has.
        miles: The integral number of miles driven on the car.
        make: The make of the car as a string.
        model: The model of the car as a string.
        year: The integral year the car was built.
        sold_on: The date the vehicle was sold.
    """

    def __init__(self, wheels, miles, make, model, year, sold_on):
        """Return a new Car object."""
        self.wheels = wheels
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on

    def sale_price(self):
        """Return the sale price for this car as a float amount."""
        if self.sold_on is not None:
            return 0.0  # Already sold
        return 5000.0 * self.wheels

    def purchase_price(self):
        """Return the price for which we would pay to purchase the car."""
        if self.sold_on is None:
            return 0.0  # Not yet sold
        return 8000 - (.10 * self.miles)

    ...

看起來非常合理。當然,類中可能還有其它方法,但我已經展示了兩個我們感興趣的方法:<font color=red>sale_price</font>和<font color=red>purchase_price</font>。我們之后會看到為什么這些很重要。

我們已經有了<font color=red>Car</font>類,也許我們應該創建<font color=red>Truck</font>類。我們按同樣的方式創建:

class Truck(object):
    """A truck for sale by Jeffco Car Dealership.

    Attributes:
        wheels: An integer representing the number of wheels the truck has.
        miles: The integral number of miles driven on the truck.
        make: The make of the truck as a string.
        model: The model of the truck as a string.
        year: The integral year the truck was built.
        sold_on: The date the vehicle was sold.
    """

    def __init__(self, wheels, miles, make, model, year, sold_on):
        """Return a new Truck object."""
        self.wheels = wheels
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on

    def sale_price(self):
        """Return the sale price for this truck as a float amount."""
        if self.sold_on is not None:
            return 0.0  # Already sold
        return 5000.0 * self.wheels

    def purchase_price(self):
        """Return the price for which we would pay to purchase the truck."""
        if self.sold_on is None:
            return 0.0  # Not yet sold
        return 10000 - (.10 * self.miles)

    ...

幾乎跟<font color=red>Car</font>類一模一樣。編程中最重要的原則之一(通常不只是處理對象時)是“DRY”或者“Don't Repeat Yourself”。確定無疑,我們在這里重復了。實際上,<font color=red>Car</font>類和<font color=red>Truck</font>類只有一個字符不同(除了注釋)。

出什么事了?我們哪里做錯了?我們的主要問題是我們直奔概念:<font color=red>Car</font>和<font color=red>Truck</font>是真實的事物,直覺讓有形的對象成為類。但是它們共享這么多數據和功能,似乎我們可以在這里引入一個抽象。沒錯,它就是<font color=red>Vehicle</font>。

抽象類

<font color=red>Vehicle</font>不是真實世界的對象。而是一個概念,它包含某些真實世界中的對象(比如汽車,卡車和摩托車)。我們可以用這個事實來移除重復代碼,即每個對象都被看做是一臺車輛。通過定義<font color=red>Vehicle</font>類達到目的:

class Vehicle(object):
    """A vehicle for sale by Jeffco Car Dealership.

    Attributes:
        wheels: An integer representing the number of wheels the vehicle has.
        miles: The integral number of miles driven on the vehicle.
        make: The make of the vehicle as a string.
        model: The model of the vehicle as a string.
        year: The integral year the vehicle was built.
        sold_on: The date the vehicle was sold.
    """

    base_sale_price = 0

    def __init__(self, wheels, miles, make, model, year, sold_on):
        """Return a new Vehicle object."""
        self.wheels = wheels
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on


    def sale_price(self):
        """Return the sale price for this vehicle as a float amount."""
        if self.sold_on is not None:
            return 0.0  # Already sold
        return 5000.0 * self.wheels

    def purchase_price(self):
        """Return the price for which we would pay to purchase the vehicle."""
        if self.sold_on is None:
            return 0.0  # Not yet sold
        return self.base_sale_price - (.10 * self.miles)

通過替換<font color=red>class Car(object)</font>中的<font color=red>object</font>,我們可以讓<font color=red>Car</font>和<font color=red>Truck</font>類繼承<font color=red>Vehicle</font>類。括號中的類表示從哪個類繼承(<font color=red>object</font>實際上是“沒有繼承”。我們一會兒討論為什么這么寫)。

現在我們可以直截了當的定義<font color=red>Car</font>和<font color=red>Truck</font>:

class Car(Vehicle):

    def __init__(self, wheels, miles, make, model, year, sold_on):
        """Return a new Car object."""
        self.wheels = wheels
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on
        self.base_sale_price = 8000


class Truck(Vehicle):

    def __init__(self, wheels, miles, make, model, year, sold_on):
        """Return a new Truck object."""
        self.wheels = wheels
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on
        self.base_sale_price = 10000

這樣可以工作了,但還有一些問題。首先我們仍然有很多重復的代碼。最終我們會處理完所有重復的代碼。其次,更大的問題是,我們引入了<font color=red>Vehicle</font>類,但我們真的允許調用者創建<font color=red>Vehicle</font>對象(而不是<font color=red>Car</font>和<font color=red>Truck</font>)?<font color=red>Vehicle</font>僅僅是一個概念,不是真實的事物,所以下面代碼的意義是:

v = Vehicle(4, 0, 'Honda', 'Accord', 2014, None)
print v.purchase_price()

<font color=red>Vehicle</font>沒有<font color=red>base_sale_price</font>,只有各個子類(比如<font color=red>Car</font>和<font color=red>Truck</font>)有。問題在于<font color=red>Vehicle</font>應該是一個Abstract Base ClassAbstract Base Class是只可以被繼承的類;不能創建ABC的實例。這意味著如果<font color=red>Vehicle</font>是一個ABC,那么下面的代碼就是非法的:

v = Vehicle(4, 0, 'Honda', 'Accord', 2014, None)

禁止這一點是有意義的,因為我們從來不會直接使用<font color=red>Vehicle</font>。我們只想用它抽取一些通用的數據和行為。我們如何讓一個類成為ABC?很簡單!<font color=red>abc</font>模塊包括一個稱為<font color=red>ABCMeta</font>的元類。設置一個類的元類為<font color=red>ABCMeta</font>,并讓其中一個方法為虛擬的,就能讓類成為一個ABCABC規定,虛擬方法必須在子類中存在,但不是必須要實現。例如,<font color=red>Vehicle</font>類可以如下定義:

from abc import ABCMeta, abstractmethod

class Vehicle(object):
    """A vehicle for sale by Jeffco Car Dealership.


    Attributes:
        wheels: An integer representing the number of wheels the vehicle has.
        miles: The integral number of miles driven on the vehicle.
        make: The make of the vehicle as a string.
        model: The model of the vehicle as a string.
        year: The integral year the vehicle was built.
        sold_on: The date the vehicle was sold.
    """

    __metaclass__ = ABCMeta

    base_sale_price = 0

    def sale_price(self):
        """Return the sale price for this vehicle as a float amount."""
        if self.sold_on is not None:
            return 0.0  # Already sold
        return 5000.0 * self.wheels

    def purchase_price(self):
        """Return the price for which we would pay to purchase the vehicle."""
        if self.sold_on is None:
            return 0.0  # Not yet sold
        return self.base_sale_price - (.10 * self.miles)

    @abstractmethod
    def vehicle_type():
        """"Return a string representing the type of vehicle this is."""
        pass

因為<font color=red>vehicle_type</font>是一個<font color=red>abstractmethod</font>,所以我們不能直接創建<font color=red>Vehicle</font>實例。只要<font color=red>Car</font>和<font color=red>Truck</font>從<font color=red>Vehicle</font>繼承,定義了<font color=red>vehicle_type</font>,我們就能實例化這些類。

返回<font color=red>Car</font>類和<font color=red>Truck</font>類中的重復代碼,看看我們是否可以把通用的功能提升到基類<font color=red>Vehicle</font>中:

from abc import ABCMeta, abstractmethod
class Vehicle(object):
    """A vehicle for sale by Jeffco Car Dealership.


    Attributes:
        wheels: An integer representing the number of wheels the vehicle has.
        miles: The integral number of miles driven on the vehicle.
        make: The make of the vehicle as a string.
        model: The model of the vehicle as a string.
        year: The integral year the vehicle was built.
        sold_on: The date the vehicle was sold.
    """

    __metaclass__ = ABCMeta

    base_sale_price = 0
    wheels = 0

    def __init__(self, miles, make, model, year, sold_on):
        self.miles = miles
        self.make = make
        self.model = model
        self.year = year
        self.sold_on = sold_on

    def sale_price(self):
        """Return the sale price for this vehicle as a float amount."""
        if self.sold_on is not None:
            return 0.0  # Already sold
        return 5000.0 * self.wheels

    def purchase_price(self):
        """Return the price for which we would pay to purchase the vehicle."""
        if self.sold_on is None:
            return 0.0  # Not yet sold
        return self.base_sale_price - (.10 * self.miles)

    @abstractmethod
    def vehicle_type(self):
        """"Return a string representing the type of vehicle this is."""
        pass

現在<font color=red>Car</font>和<font color=red>Truck</font>類變成:

class Car(Vehicle):
    """A car for sale by Jeffco Car Dealership."""

    base_sale_price = 8000
    wheels = 4

    def vehicle_type(self):
        """"Return a string representing the type of vehicle this is."""
        return 'car'

class Truck(Vehicle):
    """A truck for sale by Jeffco Car Dealership."""

    base_sale_price = 10000
    wheels = 4

    def vehicle_type(self):
        """"Return a string representing the type of vehicle this is."""
        return 'truck'

這完全符合我們的直覺:就我們的系統而言,汽車和卡車之間的唯一區別是基礎售價。

定義一個<font color=red>Motocycle</font>類非常簡單:

class Motorcycle(Vehicle):
    """A motorcycle for sale by Jeffco Car Dealership."""

    base_sale_price = 4000
    wheels = 2

    def vehicle_type(self):
        """"Return a string representing the type of vehicle this is."""
        return 'motorcycle'

繼承和LSP

盡管看起來我們用繼承處理了重復,但我們真正做的是簡單的提供適當級別的抽象。抽象是理解繼承的關鍵。我們已經看到使用繼承的一個附帶作用是減少重復的代碼,但從調用者的角度來看呢?使用繼承如何改變代碼?

事實證明有一點。想象我們有兩個類:<font color=red>Dog</font>和<font color=red>Person</font>,我們想寫一個函數,它接收任何兩種對象類型,并打印該實例是否可以說話(狗不能,人可以)。我們可能這么編寫代碼:

def can_speak(animal):
    if isinstance(animal, Person):
        return True
    elif isinstance(animal, Dog):
        return False
    else:
        raise RuntimeError('Unknown animal!')

只有兩種類型的動物時沒問題,但是如何有20種呢,或者200種?那么<font color=red>if...elif</font>會相當長。

這里關鍵是<font color=red>can_speak</font>不應該關心處理的動物類型,動物類本身應該告訴我們它能否說話。通過引入基類<font color=red>Animal</font>,其中定義<font color=red>can_speak</font>,可以避免函數的類型檢查。只要知道是傳進來的是<font color=red>Animal</font>,確定能否說話很簡單:

def can_speak(animal):
    return animal.can_speak()

這是因為<font color=red>Person</font>和<font color=red>Dog</font>(或者其它任何從<font color=red>Animal</font>繼承的類)遵循Liskov Substitution Principle。這表示我們可以在希望父類(<font color=red>Animal</font>)的地方,使用子類(比如<font color=red>Person</font>或<font color=red>Dog</font>)替換。這聽起來很簡單,但它是interface的基礎。

總結

希望你們學會了什么是Python類,為什么它們很有用,以及如何使用。類和面向對象編程很深奧。確實,它涉及計算機科學的核心。本文不是對類的詳細研究,也不應該是你的唯一參考。網絡上有數以千計的OOP和類的解釋,如果本文對你不合適,搜索會讓你找到更適合你的。

一如既往,歡迎在評論中更正和討論。只要保持禮貌就行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容