pythonic和面向對象

1 類的定義

假設需要定義一個人

# person.py
class Person:
    def __init__(self, age=18, code=3):
        self.age, self.code = age, code

    def total(self):
        return self.age + self.code

上述是一個構造函數,如果在java里面我們這樣玩,會這樣寫:

public class Person{
     private int age;
     private int code;

     public Person(age,code){
        this.age = age;
        this.code = code
  }
     getter,setter省略...
}

我們需要注意的是python這種連等方式。

from person import *
p = Person(10, 10)  # __init__ 被調用
type(p)
<class 'person.Person'>
p.age, p.code
(10, 10)

我們在person初始化的方法上寫了,2個默認值。
對一切皆對象的 Python 來說,類自己當然也是對象:

type(Person)
<class 'type'>
dir(Person)
['__class__', '__delattr__', '__dict__', ..., '__init__','total' ...]
Person.__class__
<class 'type'>

使用dir()函數可以查看對像內所有屬于及方法,在python中任何東西都是對像,一種數據類型,一個模塊等,都有自己的屬性和方法,除了常用方法外,其它的你不需要全部記住它,交給dir()函數就好了。

查看列表都有哪些方法

dir([ ])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__',
 '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__',
 '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__',
 '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count',
 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

很好,我們的到了列表所有的方法,熟悉的有append,insert等,具體不說明了。好我們繼續看

class Person:
    ...
    def set(self, x, y):
        self.x, self.y = x, y

p = Person(10, 10)
p.set(0, 0)
p.x, p.y
(0, 0)

p.set(...) 其實只是一個語法糖,你也可以寫成 Point.set(p, ...),這樣就能明顯看出 p 就是 self 參數了:

Point.set(p, 0, 0)
p.x, p.y
(0, 0)

上面這種寫法,是一樣的。

訪問控制

Python 沒有 public / protected / private 這樣的訪問控制,如果你非要表示“私有”,習慣是加雙下劃線前綴。

class Point:
    def __init__(self, x=0, y=0):
        self.__x, self.__y = x, y
 
    def set(self, x, y):
        self.__x, self.__y = x, y
 
    def __f(self):
        pass

__x、__y 和 __f 就相當于私有了:

>>> p.__x
...
AttributeError: 'Point' object has no attribute '__x'
>>> p.__f()
...
AttributeError: 'Point' object has no attribute '__f'

嘗試打印 Point 實例:

>>> p = Point(10, 10)
>>> p
<point.Point object at 0x000000000272AA20>

可以看到我們打印出了這個p對象,如果我們想換一種方式呢?

class Point:
    def __repr__(self):
        return 'Point({}, {})'.format(self.__x, self.__y)

>>> repr(p)
'Point(10, 10)'

我們在一個類中自定義了一個repr方法,調用他。下面我們來看一些野路子。。。
裝飾器@staticmethod和@classmethod有什么區別?

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x

a=A()

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1) //注意傳遞的是cls

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

一個簡單的例子很直接說明了classmethod的用法

class Kls(object):
    no_inst = 0

    def __init__(self):
        Kls.no_inst = Kls.no_inst + 1

    @classmethod
    def get_no_of_instance(cls_obj):
        return cls_obj.no_inst

ik1 = Kls()
ik2 = Kls()
ik3 = Kls()

print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
// output 3

2 類的繼承

舉一個教科書中最常見的例子。Circle 和 Rectangle 繼承自 Shape,不同的圖形,面積(area)計算方式不同。

# shape.py
 
class Shape:
    def area(self):
        return 0.0
        
class Circle(Shape):
    def __init__(self, r=0.0):
        self.r = r
 
    def area(self):
        return math.pi * self.r * self.r
 
class Rectangle(Shape):
    def __init__(self, a, b):
        self.a, self.b = a, b
 
    def area(self):
        return self.a * self.b

>>> from shape import *
>>> circle = Circle(3.0)
>>> circle.area()
28.274333882308138
>>> rectangle = Rectangle(2.0, 3.0)
>>> rectangle.area()
6.0

繼承的方式很簡單,在類名上加個括號就行。
如果 Circle 沒有定義自己的 area:

class Circle(Shape):
    pass
>>> Shape.area is Circle.area
True

一旦 Circle 定義了自己的 area,從 Shape 繼承而來的那個 area 就被重寫(overwrite)了:

>>> from shape import *
>>> Shape.area is Circle.area
False

通過類的字典更能明顯地看清這一點:

>>> Shape.__dict__['area']
<function Shape.area at 0x0000000001FDB9D8>
>>> Circle.__dict__['area']
<function Circle.area at 0x0000000001FDBB70>

所以,子類重寫父類的方法,其實只是把相同的屬性名綁定到了不同的函數對象。可見 Python 是沒有覆寫(override)的概念的。

甚至可以動態的添加方法:

class Circle(Shape):
    ...
    #  def area(self):
        #  return math.pi * self.r * self.r
 
# 為 Circle 添加 area 方法。
Circle.area = lambda self: math.pi * self.r * self.r

lambda表達式返回一個函數對象。
這樣吧我們寫一個完整的繼承代碼把


輸出

3 多態

如前所述,Python 沒有覆寫(override)的概念。嚴格來講,Python 并不支持「多態」。

#!/usr/bin/env Python
class Animal:
    def __init__(self, name=""):
        self.name = name

    def talk(self):
        pass

class Cat(Animal):
    def talk(self):
        print "Meow!"

class Dog(Animal):
    def talk(self):
        print "Woof!"

a = Animal()
a.talk()

c = Cat("Missy")
c.talk()

d = Dog("Rocky")
d.talk()

其實我沒有虎你,python里的多態看起來確實很low。。。下面講一個知識點

#!/usr/bin/env Python
class ProtectMe:
    def __init__(self):
        self.me = "qiwsir"
        self.__name = "kivi"

    @property
    def name(self):
        return self.__name

if __name__ == "__main__":
    p = ProtectMe()
    print p.name

怎么樣知道如何訪問私有屬性了把。。
最后給大家帶來一波福利,我這里只貼代碼了,大家細看

itertools庫

迭代器(生成器)在Python中是一種很常用也很好用的數據結構,比起列表(list)來說,迭代器最大的優勢就是延遲計算,按需使用,從而提高開發體驗和運行效率,以至于在Python 3中map,filter等操作返回的不再是列表而是迭代器。
itertools.accumulate

>>> import itertools
>>> x = itertools.accumulate(range(10))
>>> print(list(x))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]

原函數是這樣寫的

def accumulate(iterable, func=operator.add):
    'Return running totals'
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
    it = iter(iterable)
    try:
        total = next(it)
    except StopIteration:
        return
    yield total
    for element in it:
        total = func(total, element)
        yield total

data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]
>>> list(accumulate(data, operator.mul))     # running product
[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]

itertools.chain

>>> x = itertools.chain(range(3), range(4), [3,2,1])
>>> print(list(x))
[0, 1, 2, 0, 1, 2, 3, 3, 2, 1]

itertools.combinations
求列表或生成器中指定數目的元素不重復的所有組合

>>> x = itertools.combinations(range(4), 3)
>>> print(list(x))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]

itertools.compress
按照真值表篩選元素

>>> x = itertools.compress(range(5), (True, False, True, True, False))
>>> print(list(x))
[0, 2, 3]

itertools.islice

def islice(iterable, *args):
    # islice('ABCDEFG', 2) --> A B
    # islice('ABCDEFG', 2, 4) --> C D
    # islice('ABCDEFG', 2, None) --> C D E F G
    # islice('ABCDEFG', 0, None, 2) --> A C E G
    s = slice(*args)
    it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))
    try:
        nexti = next(it)
    except StopIteration:
        return
    for i, element in enumerate(iterable):
        if i == nexti:
            yield element
            nexti = next(it)

itertools.count(start=0, step=1)

 # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step
>>> x = itertools.count(start=20, step=-1)
>>> print(list(itertools.islice(x, 0, 5, 2)))
[20, 18, 16, 14,12]

itertools.cycle

>>> x = itertools.cycle('ABC')
>>> print(list(itertools.islice(x, 0, 10, 1)))
['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A']

itertools.filterfalse

>>> x = itertools.filterfalse(lambda e: e < 5, (1, 5, 3, 6, 9, 4))
>>> print(list(x))
[5, 6, 9]

itertools.groupby

>>> x = itertools.groupby(range(10), lambda x: x < 5 or x > 8)                                                                                                 
>>> for condition, numbers in x:                                                  
...     print(condition, list(numbers))                                                                                                        
True [0, 1, 2, 3, 4]                                                              
False [5, 6, 7, 8]                                                                
True [9]

好了,今天的講解也到這里了,我得去寫代碼了。。。

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

推薦閱讀更多精彩內容