python筆試題

python的函數(shù)參數(shù)傳遞

看兩個(gè)例子:

a = 1
def fun(a):
    a = 2
fun(a)
print a  # 1

a = []
def fun(a):
    a.append(1)
fun(a)
print a  # [1]

所有變量都可以理解為內(nèi)存中一個(gè)對(duì)象的“引用”,或者时捌,可以看做C中的viod*的感覺

這里記住的是類型是屬于對(duì)象的,而不是變量压固。而對(duì)象有兩種,“可更改”(mutable)與“不可更改”(immutable)對(duì)象巩踏。在python中秃诵,strings, tuples, 和numbers是不可更改的對(duì)象,而list,dict等則是可以修改的對(duì)象塞琼。(這就是這個(gè)問題的重點(diǎn))

當(dāng)一個(gè)引用傳遞給函數(shù)的時(shí)候,函數(shù)自動(dòng)復(fù)制一份引用,這個(gè)函數(shù)里的引用和外邊的引用沒有半毛關(guān)系了.所以第一個(gè)例子里函數(shù)把引用指向了一個(gè)不可變對(duì)象,當(dāng)函數(shù)返回的時(shí)候,外面的引用沒半毛感覺.而第二個(gè)例子就不一樣了,函數(shù)內(nèi)的引用指向的是可變對(duì)象,對(duì)它的操作就和定位了指針地址一樣,在內(nèi)存里進(jìn)行修改.

如果還不明白的話,這里有更好的解釋: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference

python中的元類(metaclass)

這個(gè)非常的不常用,但是像ORM這種復(fù)雜的結(jié)構(gòu)還是會(huì)需要的,詳情請(qǐng)看:《深刻理解Python中的元類(metaclass)》

@staticmethod和@classmethod

def foo(x):
    print "executing foo(%s)"%(x)

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

這里先理解下函數(shù)參數(shù)里面的self和cls.這個(gè)self和cls是對(duì)類或者實(shí)例的綁定,對(duì)于一般的函數(shù)來說我們可以這么調(diào)用foo(x),這個(gè)函數(shù)就是最常用的,它的工作跟任何東西(類,實(shí)例)無關(guān).對(duì)于實(shí)例方法,我們知道在類里每次定義方法的時(shí)候都需要綁定這個(gè)實(shí)例,就是foo(self, x),為什么要這么做呢?因?yàn)閷?shí)例方法的調(diào)用離不開實(shí)例,我們需要把實(shí)例自己傳給函數(shù),調(diào)用的時(shí)候是這樣的a.foo(x)(其實(shí)是foo(a, x)).類方法一樣,只不過它傳遞的是類而不是實(shí)例,A.class_foo(x).注意這里的self和cls可以替換別的參數(shù),但是python的約定是這倆,還是不要改的好.

對(duì)于靜態(tài)方法其實(shí)和普通的方法一樣,不需要對(duì)誰進(jìn)行綁定,唯一的區(qū)別是調(diào)用的時(shí)候需要使用a.static_foo(x)或者A.static_foo(x)來調(diào)用.

\ 實(shí)例方法 類方法 靜態(tài)方法
a = A() a.foo(x) A.class_foo(x) A.static_foo(x)
A 不可用 A.class_foo(x) A.static_foo(x)

更多關(guān)于這個(gè)問題:http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python

類變量和實(shí)例變量

class Person:
    name="aaa"
 
p1=Person() #類變量
p2=Person() #類變量
p1.name="bbb" #實(shí)例變量
print p1.name  # bbb
print p2.name  # aaa
print Person.name  # aaa

類變量就是供類使用的變量,實(shí)例變量就是供實(shí)例使用的.

這里p1.name="bbb"是實(shí)例調(diào)用了類變量,這其實(shí)和上面第一個(gè)問題一樣,就是函數(shù)傳參的問題,p1.name一開始是指向的類變量name="aaa",但是在實(shí)例的作用域里把類變量的引用改變了,就變成了一個(gè)實(shí)例變量,self.name不再引用Person的類變量name了.

==可以看看下面的例子: (need check)==
==python中l(wèi)ist是mutable的類變量菠净, 實(shí)例化之后也是mutable的, 所以對(duì)第一個(gè)實(shí)例的name操作彪杉, 也會(huì)引起類變量以及其它的實(shí)例中l(wèi)ist的更改==

==如何避免==

class Person:
    name=[]
 
p1=Person()
p2=Person()
p1.name.append(1)
print p1.name  # [1]
print p2.name  # [1]
print Person.name  # [1]

參考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block

python自省

這個(gè)也是python彪悍的特性.

自省就是面向?qū)ο蟮恼Z言所寫的程序在運(yùn)行時(shí),所能知道對(duì)象的類型.簡(jiǎn)單一句就是運(yùn)行時(shí)能夠獲得對(duì)象的類型.比如type(),dir(),getattr(),hasattr(),isinstance().

字典推導(dǎo)式:

d = {key: value for (key, value) in iterable}

你可以用任何方式的迭代器(元組,列表,生成器..),只要可迭代對(duì)象的元素中有兩個(gè)值.

d = {value: foo(value) for value in sequence if bar(value)}

def key_value_gen(k):
   yield chr(k+65)
   yield chr((k+13)%26+65)
d = dict(map(key_value_gen, range(26)))

python中單下劃線和雙下劃線

這篇文章討論P(yáng)ython中下劃線_的使用毅往。跟Python中很多用法類似,下劃線_的不同用法絕大部分(不全是)都是一種慣例約定派近。

單下劃線(_)

主要有三種情況:

  1. 解釋器中

_符號(hào)是指交互解釋器中最后一次執(zhí)行語句的返回結(jié)果攀唯。這種用法最初出現(xiàn)在CPython解釋器中,其他解釋器后來也都跟進(jìn)了渴丸。

>>> _
Traceback (most recent call last):
  File "", line 1, in 
NameError: name '_' is not defined
>>> 42
>>> _
42
>>> 'alright!' if _ else ':('
'alright!'
>>> _
'alright!'
  1. 作為名稱使用

這個(gè)跟上面有點(diǎn)類似侯嘀。_用作被丟棄的名稱。按照慣例曙强,這樣做可以讓閱讀你代碼的人知道残拐,這是個(gè)不會(huì)被使用的特定名稱。舉個(gè)例子碟嘴,你可能無所謂一個(gè)循環(huán)計(jì)數(shù)的值:

n = 42
for _ in range(n):
    do_something()
  1. i18n

_還可以被用作函數(shù)名。這種情況囊卜,單下劃線經(jīng)常被用作國(guó)際化和本地化字符串翻譯查詢的函數(shù)名娜扇。這種慣例好像起源于C語言。舉個(gè)例子栅组,在 Django documentation for translation 中你可能會(huì)看到:

from django.utils.translation import ugettext as _
from django.http import HttpResponse

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

第二種和第三種用法會(huì)引起沖突雀瓢,所以在任意代碼塊中,如果使用了_作i18n翻譯查詢函數(shù)玉掸,就應(yīng)該避免再用作被丟棄的變量名刃麸。

單下劃線前綴的名稱(例如_shahriar)

以單下劃線做前綴的名稱指定了這個(gè)名稱是“私有的”。在 有些 導(dǎo)入import * 的場(chǎng)景中司浪,下一個(gè)使用你代碼的人(或者你本人)會(huì)明白這個(gè)名稱僅內(nèi)部使用泊业。Python documentation里面寫道:

a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

之所以說在在 有些 import * 的場(chǎng)景,是因?yàn)閷?dǎo)入時(shí)解釋器確實(shí)對(duì)單下劃線開頭的名稱做了處理啊易。如果你這么寫from <module/package> import *吁伺,任何以單下劃線開頭的名稱都不會(huì)被導(dǎo)入,除非模塊/包的__all__列表明確包含了這些名稱租谈。更多相關(guān)信息見““Importing * in Python”篮奄。

雙下劃線前綴的名稱(例如__shahriar

以雙下劃線做前綴的名稱(特別是方法名)并不是一種慣例;它對(duì)解釋器有特定含義。Python會(huì)改寫這些名稱窟却,以免與子類中定義的名稱產(chǎn)生沖突昼丑。Python documentation中提到,任何__spam這種形式(至少以兩個(gè)下劃線做開頭夸赫,絕大部分都還有一個(gè)下劃線做結(jié)尾)的標(biāo)識(shí)符菩帝,都會(huì)文本上被替換為_classname__spam,其中classname是當(dāng)前類名憔足,并帶上一個(gè)下劃線做前綴胁附。
看下面這個(gè)例子:

>>> class A(object):
...     def _internal_use(self):
...         pass
...     def __method_name(self):
...         pass
... 
>>> dir(A())
['_A__method_name', ..., '_internal_use']

正如所料,_internal_use沒有變化滓彰,但__method_name被改寫成了_ClassName__method_name】仄蓿現(xiàn)在創(chuàng)建一個(gè)A的子類B(這可不是個(gè)好名字),就不會(huì)輕易的覆蓋掉A中的__method_name了:

>>> class B(A):
...     def __method_name(self):
...         pass
... 
>>> dir(B())
['_A__method_name', '_B__method_name', ..., '_internal_use']

這種特定的行為差不多等價(jià)于Java中的final方法和C++中的正常方法(非虛方法)揭绑。

前后都帶有雙下劃線的名稱(例如__init__

這些是Python的特殊方法名弓候,這僅僅是一種慣例,一種確保Python系統(tǒng)中的名稱不會(huì)跟用戶自定義的名稱發(fā)生沖突的方式他匪。通常你可以覆寫這些方法菇存,在Python調(diào)用它們時(shí),產(chǎn)生你想得到的行為邦蜜。例如依鸥,當(dāng)寫一個(gè)類的時(shí)候經(jīng)常會(huì)覆寫__init__方法。
你也可以寫出自己的“特殊方法”名(但是別這么做):

>>> class C(object):
...     def __mine__(self):
...         pass
...
>>> dir(C)
... [..., '__mine__', ...]

還是不要這樣寫方法名悼沈,只讓Python定義的特殊方法名使用這種慣例吧贱迟。

詳情見:http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python

或者: http://www.zhihu.com/question/19754941

字符串格式化:%和.format

.format在許多方面看起來更便利.對(duì)于%最煩人的是它無法同時(shí)傳遞一個(gè)變量和元組.你可能會(huì)想下面的代碼不會(huì)有什么問題:

hi there %s" % name

但是,如果name恰好是(1,2,3),它將會(huì)拋出一個(gè)TypeError異常.為了保證它總是正確的,你必須這樣做:

hi there %s" % (name,) # 提供一個(gè)單元素的數(shù)組而不是一個(gè)參數(shù)

但是有點(diǎn)丑..format就沒有這些問題.你給的第二個(gè)問題也是這樣,.format好看多了.

你為什么不用它?

不知道它(在讀這個(gè)之前)
為了和Python2.5兼容(譬如logging庫(kù)建議使用%(issue #4))

http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format

迭代器和生成器

這個(gè)是stackoverflow里python排名第一的問題,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python

這是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html

Iterables

當(dāng)你創(chuàng)建了一個(gè)列表,你可以一個(gè)一個(gè)的讀取它的每一項(xiàng),這叫做iteration:

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

Mylist是可迭代的.當(dāng)你用列表推導(dǎo)式的時(shí)候,你就創(chuàng)建了一個(gè)列表,而這個(gè)列表也是可迭代的:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4

所有你可以用在for...in...語句中的都是可迭代的:比如lists,strings,files...因?yàn)檫@些可迭代的對(duì)象你可以隨意的讀取所以非常方便易用,但是你必須把它們的值放到內(nèi)存里,當(dāng)它們有很多值時(shí)就會(huì)消耗太多的內(nèi)存.

Generators

生成器也是迭代器的一種,但是你只能迭代它們一次.原因很簡(jiǎn)單,因?yàn)樗鼈儾皇侨看嬖趦?nèi)存里,它們只在要調(diào)用的時(shí)候在內(nèi)存里生成:

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

生成器和迭代器的區(qū)別就是用()代替[],還有你不能用for i in mygenerator第二次調(diào)用生成器:首先計(jì)算0,然后會(huì)在內(nèi)存里丟掉0去計(jì)算1,直到計(jì)算完4.

Yield

Yield的用法和關(guān)鍵字return差不多,下面的函數(shù)將會(huì)返回一個(gè)生成器:

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() # 創(chuàng)建生成器
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

在這里這個(gè)例子好像沒什么用,不過當(dāng)你的函數(shù)要返回一個(gè)非常大的集合并且你希望只讀一次的話,那么它就非常的方便了.

要理解Yield你必須先理解當(dāng)你調(diào)用函數(shù)的時(shí)候,函數(shù)里的代碼并沒有運(yùn)行.函數(shù)僅僅返回生成器對(duì)象,這就是它最微妙的地方:-)

然后呢,每當(dāng)for語句迭代生成器的時(shí)候你的代碼才會(huì)運(yùn)轉(zhuǎn).

現(xiàn)在,到了最難的部分:

當(dāng)for語句第一次調(diào)用函數(shù)里返回的生成器對(duì)象,函數(shù)里的代碼就開始運(yùn)作,直到碰到y(tǒng)ield,然后會(huì)返回本次循環(huán)的第一個(gè)返回值.所以下一次調(diào)用也將運(yùn)行一次循環(huán)然后返回下一個(gè)值,直到?jīng)]有值可以返回.

一旦函數(shù)運(yùn)行并沒有碰到y(tǒng)eild語句就認(rèn)為生成器已經(jīng)為空了.原因有可能是循環(huán)結(jié)束或者沒有滿足if/else之類的.

Itertools你的好基友

itertools模塊包含了一些特殊的函數(shù)可以操作可迭代對(duì)象.有沒有想過復(fù)制一個(gè)生成器?鏈接兩個(gè)生成器?把嵌套列表里的值組織成一個(gè)列表?Map/Zip還不用創(chuàng)建另一個(gè)列表?

來吧import itertools

來一個(gè)例子?讓我們看看4匹馬比賽有多少個(gè)排名結(jié)果:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
 (1, 2, 4, 3),
 (1, 3, 2, 4),
 (1, 3, 4, 2),
 (1, 4, 2, 3),
 (1, 4, 3, 2),
 (2, 1, 3, 4),
 (2, 1, 4, 3),
 (2, 3, 1, 4),
 (2, 3, 4, 1),
 (2, 4, 1, 3),
 (2, 4, 3, 1),
 (3, 1, 2, 4),
 (3, 1, 4, 2),
 (3, 2, 1, 4),
 (3, 2, 4, 1),
 (3, 4, 1, 2),
 (3, 4, 2, 1),
 (4, 1, 2, 3),
 (4, 1, 3, 2),
 (4, 2, 1, 3),
 (4, 2, 3, 1),
 (4, 3, 1, 2),
 (4, 3, 2, 1)]

理解迭代的內(nèi)部機(jī)制

迭代是可迭代對(duì)象(對(duì)應(yīng)iter()方法)和迭代器(對(duì)應(yīng)next()方法)的一個(gè)過程.可迭代對(duì)象就是任何你可以迭代的對(duì)象(廢話啊).迭代器就是可以讓你迭代可迭代對(duì)象的對(duì)象(有點(diǎn)繞口,意思就是這個(gè)意思)

*args and **kwargs

用*args和**kwargs只是為了方便并沒有強(qiáng)制使用它們.

當(dāng)你不確定你的函數(shù)里將要傳遞多少參數(shù)時(shí)你可以用*args.例如,它可以傳遞任意數(shù)量的參數(shù):

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

相似的,**kwargs允許你使用沒有事先定義的參數(shù)名:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

*args和**kwargs 必須放在參數(shù)列表的后面。

面向切面編程AOP和裝飾器

這個(gè)AOP一聽起來有點(diǎn)懵,同學(xué)面阿里的時(shí)候就被問懵了…

  • 裝飾器就是把其它函數(shù)當(dāng)參數(shù)的函數(shù)絮供。
    裝飾器是一個(gè)很著名的設(shè)計(jì)模式衣吠,經(jīng)常被用于有切面需求的場(chǎng)景,較為經(jīng)典的有插入日志壤靶、性能測(cè)試缚俏、事務(wù)處理等。裝飾器是解決這類問題的絕佳設(shè)計(jì)贮乳,有了裝飾器忧换,我們就可以抽離出大量函數(shù)中與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。概括的講塘揣,裝飾器的作用就是為已經(jīng)存在的對(duì)象添加額外的功能包雀。

這個(gè)問題比較大,推薦: http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python

中文: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/3/README.html

  • 看一個(gè)簡(jiǎn)單的例子
# 字體變粗裝飾器
def makebold(fn):
    # 裝飾器將返回新的函數(shù)
    def wrapper():
        # 在之前或者之后插入新的代碼
        return "<b>" + fn() + "</b>"
    return wrapper

# 斜體裝飾器

def makeitalic(fn):
# 裝飾器將返回新的函數(shù)
def wrapper():
# 在之前或者之后插入新的代碼
return "<i>" + fn() + "</i>"
return wrapper

@makebold
@makeitalic
def say():
return "hello"

print say()

輸出: <b><i>hello</i></b>

這相當(dāng)于

def say():
return "hello"
say = makebold(makeitalic(say))

print say()

輸出: <b><i>hello</i></b>

- 用法:
    1. 傳統(tǒng)用法是給外部的不可更改的庫(kù)做擴(kuò)展
    2. Django用裝飾器管理緩存和試圖的權(quán)限.
    3. Twisted用來修改異步函數(shù)的調(diào)用.
    4. etc.

# 鴨子類型
“當(dāng)看到一只鳥走起來像鴨子、游泳起來像鴨子亲铡、叫起來也像鴨子才写,那么這只鳥就可以被稱為鴨子葡兑。”

我們并不關(guān)心對(duì)象是什么類型赞草,到底是不是鴨子讹堤,只關(guān)心行為。

比如在python中厨疙,有很多file-like的東西洲守,比如StringIO,GzipFile,socket。它們有很多相同的方法沾凄,我們把它們當(dāng)作文件使用梗醇。

又比如list.extend()方法中,我們并不關(guān)心它的參數(shù)是不是list,只要它是可迭代的,所以它的參數(shù)可以是list/tuple/dict/字符串/生成器等.

鴨子類型在動(dòng)態(tài)語言中經(jīng)常使用,非常靈活撒蟀,使得python不想java那樣專門去弄一大堆的設(shè)計(jì)模式叙谨。

# Python中重載
引自知乎:http://www.zhihu.com/question/20053359

函數(shù)重載主要是為了解決兩個(gè)問題:

  - 可變參數(shù)類型
  - 可變參數(shù)個(gè)數(shù)

另外,一個(gè)基本的設(shè)計(jì)原則是保屯,僅僅當(dāng)兩個(gè)函數(shù)除了參數(shù)類型和參數(shù)個(gè)數(shù)不同以外手负,其功能是完全相同的,此時(shí)才使用函數(shù)重載姑尺,如果兩個(gè)函數(shù)的功能其實(shí)不同竟终,那么不應(yīng)當(dāng)使用重載,而應(yīng)當(dāng)使用一個(gè)名字不同的函數(shù)切蟋。

好吧统捶,那么對(duì)于情況 1 ,函數(shù)功能相同柄粹,但是參數(shù)類型不同瘾境,python 如何處理?答案是根本不需要處理镰惦,因?yàn)?python 可以接受任何類型的參數(shù),如果函數(shù)的功能相同犬绒,那么不同的參數(shù)類型在 python 中很可能是相同的代碼旺入,沒有必要做成兩個(gè)不同函數(shù)。

那么對(duì)于情況 2 凯力,函數(shù)功能相同茵瘾,但參數(shù)個(gè)數(shù)不同,python 如何處理咐鹤?大家知道拗秘,答案就是缺省參數(shù)。對(duì)那些缺少的參數(shù)設(shè)定為缺省參數(shù)即可解決問題祈惶。因?yàn)槟慵僭O(shè)函數(shù)功能相同雕旨,那么那些缺少的參數(shù)終歸是需要用的扮匠。

好了,鑒于情況 1 跟 情況 2 都有了解決方案凡涩,==python 自然就不需要函數(shù)重載了==

# 新式類與舊式類
這個(gè)面試官問了,我說了老半天,不知道他問的真正意圖是什么.

stackoverflow(http://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python)

這篇文章很好的介紹了新式類的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html

簡(jiǎn)單的說棒搜,新式類是在創(chuàng)建的時(shí)候繼承內(nèi)置object對(duì)象(或者是從內(nèi)置類型,如list,dict等)活箕,而經(jīng)典類是直
接聲明的力麸。使用dir()方法也可以看出新式類中定義很多新的屬性和方法,而經(jīng)典類好像就2個(gè):

新式類很早在2.2就出現(xiàn)了,所以舊式類完全是兼容的問題,Python3里的類全部都是新式類.這里有一個(gè)MRO問題可以了解下(新式類是廣度優(yōu)先,舊式類是深度優(yōu)先),<Python核心編程>里講的也很多.

新式類

class C(object):
pass

經(jīng)典類

class B:
pass

# `__new__`和`__init__`的區(qū)別
這個(gè)`__new__`確實(shí)很少見到,先做了解吧.

`__new__`是一個(gè)靜態(tài)方法,而`__init__`是一個(gè)實(shí)例方法.

`__new__`方法會(huì)返回一個(gè)創(chuàng)建的實(shí)例,而`__init__`什么都不返回.

只有在`__new__`返回一個(gè)cls的實(shí)例時(shí)后面的`__init__`才能被調(diào)用.

當(dāng)創(chuàng)建一個(gè)新實(shí)例時(shí)調(diào)用`__new__`,初始化一個(gè)實(shí)例時(shí)用`__init__`.

stackoverflow(http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init)

ps: `__metaclass__`是創(chuàng)建類時(shí)起作用.所以我們可以分別使用`__metaclass__`,`__new__`和`__init__`來分別在類創(chuàng)建,實(shí)例創(chuàng)建和實(shí)例初始化的時(shí)候做一些小手腳.

# 單例模式
==這個(gè)絕對(duì)長(zhǎng)考育韩, 絕對(duì)要記住1~2個(gè)方法.==

所謂單例克蚂,是指一個(gè)類的實(shí)例從始至終只能被創(chuàng)建一次。

## 使用`__new__`方法

class Singleton(object):
def new(cls,args,kwargs):
if not hasattr(cls,'_inst'):
cls._inst=super(Singleton,cls).new(cls,
args,**kwargs)
return cls._inst
if name=='main':
class A(Singleton):
def init(self,s):
self.s=s
a=A('apple')
b=A('banana')
print id(a),a.s
print id(b),b.s

結(jié)果:

29922256 banana
29922256 banana

通過`__new__`方法筋讨,將類的實(shí)例在創(chuàng)建的時(shí)候綁定到類屬性`_inst`上埃叭。如果`cls._inst`為None,說明類還未實(shí)例化版仔,實(shí)例化并將實(shí)例綁定到`cls._inst`游盲,以后每次實(shí)例化的時(shí)候都返回第一次實(shí)例化創(chuàng)建的實(shí)例。注意從Singleton派生子類的時(shí)候蛮粮,不要重載`__new__`益缎。
## 共享屬性
有時(shí)候我們并不關(guān)心生成的實(shí)例是否具有同一id,而只關(guān)心其狀態(tài)和行為方式然想。我們可以允許許多個(gè)實(shí)例被創(chuàng)建莺奔,但所有的實(shí)例都共享狀態(tài)和行為方式:

class Borg(object):
_shared_state={}
def new(cls,args,kwargs):
obj=super(Borg,cls).new(cls,
args,**kwargs)
obj.dict=cls._shared_state
return obj

將所有實(shí)例的__dict__指向同一個(gè)字典,這樣實(shí)例就共享相同的方法和屬性变泄。對(duì)任何實(shí)例的名字屬性的設(shè)置令哟,無論是在__init__中修改還是直接修改,所有的實(shí)例都會(huì)受到影響妨蛹。不過實(shí)例的id是不同的屏富。要保證類實(shí)例能共享屬性,但不和子類共享蛙卤,注意使用cls._shared_state,而不是Borg._shared_state狠半。

因?yàn)閷?shí)例是不同的id,所以每個(gè)實(shí)例都可以做字典的key:

if name=='main':
class Example(Borg):
pass
a=Example()
b=Example()
c=Example()
adict={}
j=0
for i in a,b,c:
adict[i]=j
j+=1
for i in a,b,c:
print adict[i]
結(jié)果:
0
1
2

如果這種行為不是你想要的颤难,可以為Borg類添加__eq__和__hash__方法神年,使其更接近于單例模式的行為:

class Borg(object):
_shared_state={}
def new(cls,args,kwargs):
obj=super(Borg,cls).new(cls,
args,**kwargs)
obj.dict=cls._shared_state
return obj
def hash(self):
return 1
def eq(self,other):
try:
return self.dict is other.dict
except:
return False
if name=='main':
class Example(Borg):
pass
a=Example()
b=Example()
c=Example()
adict={}
j=0
for i in a,b,c:
adict[i]=j
j+=1
for i in a,b,c:
print adict[i]
結(jié)果:
2
2
2

所有的實(shí)例都能當(dāng)一個(gè)key使用了。
## 裝飾器版本

def singleton(cls, *args, *kw):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls(
args, **kw)
return instances[cls]
return getinstance

@singleton
class MyClass:
...

## 基于元組
當(dāng)你編寫一個(gè)類的時(shí)候行嗤,某種機(jī)制會(huì)使用類名字已日,基類元組,類字典來創(chuàng)建一個(gè)類對(duì)象栅屏。新型類中這種機(jī)制默認(rèn)為type飘千,而且這種機(jī)制是可編程的堂鲜,稱為元類__metaclass__ 。

class Singleton(type):
def init(self,name,bases,class_dict):
super(Singleton,self).init(name,bases,class_dict)
self._instance=None
def call(self,args,kwargs):
if self._instance is None:
self._instance=super(Singleton,self).call(
args,**kwargs)
return self._instance
if name=='main':
class A(object):
metaclass=Singleton
a=A()
b=A()
print id(a),id(b)
結(jié)果:

34248016 34248016

id是相同的占婉。

例子中我們構(gòu)造了一個(gè)Singleton元類泡嘴,并使用`__call__`方法使其能夠模擬函數(shù)的行為。構(gòu)造類A時(shí)逆济,將其元類設(shè)為Singleton酌予,那么創(chuàng)建類對(duì)象A時(shí),行為發(fā)生如下:

`A=Singleton(name,bases,class_dict)`,A其實(shí)為Singleton類的一個(gè)實(shí)例奖慌。

創(chuàng)建A的實(shí)例時(shí)抛虫,`A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__()`,這樣就將A的所有實(shí)例都指向了A的屬性`_instance`上简僧,這種方法與方法1其實(shí)是相同的建椰。
## import方法
作為python的模塊是天然的單例模式

mysingleton.py

class My_Singleton(object):
def foo(self):
pass

my_singleton = My_Singleton()

to use

from mysingleton import my_singleton

my_singleton.foo()

## python中的作用域
Python 中,一個(gè)變量的作用域總是由在代碼中被賦值的地方所決定的岛马。

當(dāng) Python 遇到一個(gè)變量的話他會(huì)按照這樣的順序進(jìn)行搜索:

本地作用域(Local)→當(dāng)前作用域被嵌入的本地作用域(Enclosing locals)→全局/模塊作用域(Global)→內(nèi)置作用域(Built-in)
## GIL線程全局鎖

線程全局鎖(Global Interpreter Lock),即Python為了保證線程安全而采取的獨(dú)立線程運(yùn)行的限制,說白了就是一個(gè)核只能在同一時(shí)間運(yùn)行一個(gè)線程.

見Python 最難的問題http://www.oschina.net/translate/pythons-hardest-problem

==解決辦法就是多進(jìn)程和下面的協(xié)程(協(xié)程也只是單CPU,但是能減小切換代價(jià)提升性能).==
## 協(xié)程
知乎被問到了,呵呵噠,跪了

簡(jiǎn)單點(diǎn)說協(xié)程是進(jìn)程和線程的升級(jí)版,進(jìn)程和線程都面臨著內(nèi)核態(tài)和用戶態(tài)的切換問題而耗費(fèi)許多切換時(shí)間,而協(xié)程就是用戶自己控制切換的時(shí)機(jī),不再需要陷入系統(tǒng)的內(nèi)核態(tài).

Python里最常見的yield就是協(xié)程的思想!可以查看第九個(gè)問題.
## 閉包
閉包(closure)是函數(shù)式編程的重要的語法結(jié)構(gòu)棉姐。閉包也是一種組織代碼的結(jié)構(gòu),它同樣提高了代碼的可重復(fù)使用性啦逆。

當(dāng)一個(gè)內(nèi)嵌函數(shù)引用其外部作作用域的變量,我們就會(huì)得到一個(gè)閉包. 總結(jié)一下,創(chuàng)建一個(gè)閉包必須滿足以下幾點(diǎn):

必須有一個(gè)內(nèi)嵌函數(shù)
內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量
外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)

感覺閉包還是有難度的,幾句話是說不明白的,還是查查相關(guān)資料.

重點(diǎn)是函數(shù)運(yùn)行后并不會(huì)被撤銷,就像16題的instance字典一樣,當(dāng)函數(shù)運(yùn)行完后,instance并不被銷毀,而是繼續(xù)留在內(nèi)存空間里.這個(gè)功能類似類里的類變量,只不過遷移到了函數(shù)上.

閉包就像個(gè)空心球一樣,你知道外面和里面,但你不知道中間是什么樣.
## lambda函數(shù)
其實(shí)就是一個(gè)匿名函數(shù),為什么叫l(wèi)ambda?因?yàn)楹秃竺娴暮瘮?shù)式編程有關(guān).

推薦: 知乎(http://www.zhihu.com/question/20125256 )
## python函數(shù)式編程
這個(gè)需要適當(dāng)?shù)牧私庖幌掳?畢竟函數(shù)式編程在Python中也做了引用.

推薦: 酷殼(http://coolshell.cn/articles/10822.html )

python中函數(shù)式編程支持:

filter 函數(shù)的功能相當(dāng)于過濾器伞矩。調(diào)用一個(gè)布爾函數(shù)bool_func來迭代遍歷每個(gè)seq中的元素;返回一個(gè)使bool_seq返回值為true的元素的序列夏志。

a = [1,2,3,4,5,6,7]
b = filter(lambda x: x > 5, a)
print b
[6,7]

map函數(shù)是對(duì)一個(gè)序列的每個(gè)項(xiàng)依次執(zhí)行函數(shù)乃坤,下面是對(duì)一個(gè)序列每個(gè)項(xiàng)都乘以2:

a = map(lambda x:x*2,[1,2,3])
list(a)
[2, 4, 6]

reduce函數(shù)是對(duì)一個(gè)序列的每個(gè)項(xiàng)迭代調(diào)用函數(shù),下面是求3的階乘:

reduce(lambda x,y:x*y,range(1,4))
6

## python里的拷貝
引用和copy(),deepcopy()的區(qū)別:
1. copy.copy 淺拷貝 只拷貝父對(duì)象沟蔑,不會(huì)拷貝對(duì)象的內(nèi)部的子對(duì)象湿诊。
2. copy.deepcopy 深拷貝 拷貝對(duì)象及其子對(duì)象
3. copy拷貝一個(gè)對(duì)象,但是對(duì)象的屬性還是引用原來的瘦材,deepcopy拷貝一個(gè)對(duì)象厅须,把對(duì)象里面的屬性也做了拷貝,deepcopy之后完全是另一個(gè)對(duì)象了

import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始對(duì)象

b = a #賦值食棕,傳對(duì)象的引用
c = copy.copy(a) #對(duì)象拷貝九杂,淺拷貝,里面的[]還是引用原來的
d = copy.deepcopy(a) #對(duì)象拷貝,深拷貝宣蠕, 所有的屬性引用全部是新的

a.append(5) #修改對(duì)象a
a[4].append('c') #修改對(duì)象a中的['a', 'b']數(shù)組對(duì)象

print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d

輸出結(jié)果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]

## python 垃圾回收機(jī)制
Python GC主要使用引用計(jì)數(shù)(reference counting)來跟蹤和回收垃圾。在引用計(jì)數(shù)的基礎(chǔ)上甥捺,通過“標(biāo)記-清除”(mark and sweep)解決容器對(duì)象可能產(chǎn)生的循環(huán)引用問題抢蚀,通過“分代回收”(generation collection)以空間換時(shí)間的方法提高垃圾回收效率。
### 引用計(jì)數(shù)
PyObject是每個(gè)對(duì)象必有的內(nèi)容镰禾,其中`ob_refcnt`就是做為引用計(jì)數(shù)皿曲。當(dāng)一個(gè)對(duì)象有新的引用時(shí)唱逢,它的`ob_refcnt`就會(huì)增加,當(dāng)引用它的對(duì)象被刪除屋休,它的ob_refcnt就會(huì)減少.引用計(jì)數(shù)為0時(shí)坞古,該對(duì)象生命就結(jié)束了。

- 優(yōu)點(diǎn):

  - 簡(jiǎn)單
  - 實(shí)時(shí)性

- 缺點(diǎn):

  - 維護(hù)引用計(jì)數(shù)消耗資源
  - 循環(huán)引用

## 標(biāo)記\-清楚機(jī)制
基本思路是先按需分配劫樟,等到?jīng)]有空閑內(nèi)存的時(shí)候從寄存器和程序棧上的引用出發(fā)痪枫,遍歷以對(duì)象為節(jié)點(diǎn)、以引用為邊構(gòu)成的圖叠艳,把所有可以訪問到的對(duì)象打上標(biāo)記奶陈,然后清掃一遍內(nèi)存空間,把所有沒標(biāo)記的對(duì)象釋放附较。
## 分代技術(shù)
分代回收的整體思想是:將系統(tǒng)中的所有內(nèi)存塊根據(jù)其存活時(shí)間劃分為不同的集合吃粒,每個(gè)集合就成為一個(gè)“代”,垃圾收集頻率隨著“代”的存活時(shí)間的增大而減小拒课,存活時(shí)間通常利用經(jīng)過幾次垃圾回收來度量徐勃。

Python默認(rèn)定義了三代對(duì)象集合,索引數(shù)越大早像,對(duì)象存活時(shí)間越長(zhǎng)僻肖。

舉例:
  當(dāng)某些內(nèi)存塊M經(jīng)過了3次垃圾收集的清洗之后還存活時(shí),我們就將內(nèi)存塊M劃到一個(gè)集合A中去扎酷,而新分配的內(nèi)存都劃分到集合B中去檐涝。當(dāng)垃圾收集開始工作時(shí),大多數(shù)情況都只對(duì)集合B進(jìn)行垃圾回收法挨,而對(duì)集合A進(jìn)行垃圾回收要隔相當(dāng)長(zhǎng)一段時(shí)間后才進(jìn)行谁榜,這就使得垃圾收集機(jī)制需要處理的內(nèi)存少了,效率自然就提高了凡纳。在這個(gè)過程中窃植,集合B中的某些內(nèi)存塊由于存活時(shí)間長(zhǎng)而會(huì)被轉(zhuǎn)移到集合A中,當(dāng)然荐糜,集合A中實(shí)際上也存在一些垃圾巷怜,這些垃圾的回收會(huì)因?yàn)檫@種分代的機(jī)制而被延遲。
# python的list
推薦: http://www.reibang.com/p/J4U6rR (c語言的實(shí)現(xiàn))
- 基本列表操作:
    - 刪除  
    `del list[2]`
    - 分片賦值  
    `name[2:] = list('ar')`
- append

list.append(2)

- count

x = [[1,2],1,1,[2,1,[1,2]]]
x.count([1,2])
1
x.count(1)
2

- append
用于在列表末尾追加新的對(duì)象

lst = [1,2,3,4]
lst.append[4]
lst
[1,2,3,4]

- extend
可以在列表末尾一次性追加另一個(gè)序列的多個(gè)值

a = [1,2,3]
b = [4,5,6]
a.extend(b)
a
[1,2,3,4,5,6]

看起來與`a+b`操作很像暴氏, 但是extend方法修改了被擴(kuò)展序列延塑,而`a+b`則是返回新的序列

a = [1,2,3]
b = [4,5,6]
a+b
[1,2,3,4,5,6]
a
[1,2,3]

- index方法
查找元素在列表中的位置

L= [1,2,3,3]
[1,2,3,3]
L.index(3)
2

- insert方法

L= [1,2,3]
[1,2,3]
L.insert(0,10)
[10,1,2,3]

- pop方法

L= [1,2,3]
[1,2,3]
L.pop(0)
1
L
[2,3]

Perl的列表array里面pop只能彈出右側(cè)的一個(gè)元素, 而這個(gè)可以彈出指定的index元素
有返回值答渔, 返回值是彈出的元素关带, 并且修改了原列表
- remove方法
移除列表中某個(gè)值的第一個(gè)匹配項(xiàng)

L= [1,2,3,3,4]
[1,2,3,3,4]
L.remove(3)
L
[1,2,3,4]

沒有返回值,原位修改
- sort方法
sort方法用于在原位置對(duì)列表進(jìn)行排序沼撕。

L= [1,2,3,5,4]
L.sort()
L
[1,2,3,4,5]

- reverse方法

L= [1,2,3,3,4]
[1,2,3,3,4]
L.reverse()
L
[4,3,3,2,1]

- sort 與sorted()的關(guān)系
- 相同:
    - 都是排序
    - 都支持key, reverse參數(shù)宋雏, 其中key的話可以實(shí)現(xiàn)高級(jí)排序
- 不同
    -  sort只對(duì)list起作用芜飘, 而sorted是全局函數(shù),對(duì)任何可迭代的序列均可以使用
    -  sort是原位修改,而sorted()會(huì)返回新的列表

詳情請(qǐng)看( https://github.com/qiwsir/algorithm/blob/master/python_sort.md )

# python的is
is是對(duì)比地址,==是對(duì)比值
# read, readline和readlines
- read 讀取整個(gè)文件
- readline 讀取下一行,使用生成器方法
- readlines 讀取整個(gè)文件到一個(gè)迭代器以供我們遍歷

# python2和3的區(qū)別
推薦:《Python 2.7.x 和 3.x 版本的重要區(qū)別》http://python.jobbole.com/80006/
# 操作系統(tǒng)
## select,poll和epoll
其實(shí)所有的I/O都是輪詢的方法,只不過實(shí)現(xiàn)的層面不同罷了.

這個(gè)問題可能有點(diǎn)深入了,但相信能回答出這個(gè)問題是對(duì)I/O多路復(fù)用有很好的了解了.其中tornado使用的就是epoll的.

selec,poll和epoll區(qū)別總結(jié)(http://www.cnblogs.com/Anker/p/3265058.html )

基本上select有3個(gè)缺點(diǎn):

  - 連接數(shù)受限
  - 查找配對(duì)速度慢
  - 數(shù)據(jù)由內(nèi)核拷貝到用戶態(tài)

poll改善了第一個(gè)缺點(diǎn)

epoll改了三個(gè)缺點(diǎn).

關(guān)于epoll的: http://www.cnblogs.com/my_life/articles/3968782.html
## 調(diào)度算法
1. 先來先服務(wù)(FCFS, First Come First Serve)
2. 短作業(yè)優(yōu)先(SJF, Shortest Job First)
3. 最高優(yōu)先權(quán)調(diào)度(Priority Scheduling)
4. 時(shí)間片輪轉(zhuǎn)(RR, Round Robin)
5. 多級(jí)反饋隊(duì)列調(diào)度(multilevel feedback queue
6. scheduling)

- 實(shí)時(shí)調(diào)度算法:

1. 最早截至?xí)r間優(yōu)先 EDF
2. 最低松弛度優(yōu)先 LLF

## 死鎖
- 原因:

1. 競(jìng)爭(zhēng)資源
2. 程序推進(jìn)順序不當(dāng)

- 必要條件:

1. 互斥條件
2. 請(qǐng)求和保持條件
3. 不剝奪條件
4. 環(huán)路等待條件

- 處理死鎖基本方法:

1. 預(yù)防死鎖(摒棄除1以外的條件)
2. 避免死鎖(銀行家算法)
3. 檢測(cè)死鎖(資源分配圖)
4. 解除死鎖
    1. 剝奪資源
    2. 撤銷進(jìn)程

## 程序編譯與鏈接
推薦: http://www.ruanyifeng.com/blog/2014/11/compiler.html

Bulid過程可以分解為4個(gè)步驟:預(yù)處理(Prepressing), 編譯(Compilation)、匯編(Assembly)椭更、鏈接(Linking)

以c語言為例:

- 預(yù)處理

預(yù)編譯過程主要處理那些源文件中的以“#”開始的預(yù)編譯指令,主要處理規(guī)則有:

將所有的“#define”刪除娶牌,并展開所用的宏定義
處理所有條件預(yù)編譯指令,比如“#if”邻薯、“#ifdef”裙戏、 “#elif”、“#endif”
處理“#include”預(yù)編譯指令厕诡,將被包含的文件插入到該編譯指令的位置累榜,注:此過程是遞歸進(jìn)行的
刪除所有注釋
添加行號(hào)和文件名標(biāo)識(shí),以便于編譯時(shí)編譯器產(chǎn)生調(diào)試用的行號(hào)信息以及用于編譯時(shí)產(chǎn)生編譯錯(cuò)誤或警告時(shí)可顯示行號(hào)
保留所有的#pragma編譯器指令灵嫌。

- 編譯

編譯過程就是把預(yù)處理完的文件進(jìn)行一系列的詞法分析壹罚、語法分析、語義分析及優(yōu)化后生成相應(yīng)的匯編代碼文件寿羞。這個(gè)過程是整個(gè)程序構(gòu)建的核心部分猖凛。

- 匯編

匯編器是將匯編代碼轉(zhuǎn)化成機(jī)器可以執(zhí)行的指令,每一條匯編語句幾乎都是一條機(jī)器指令绪穆。經(jīng)過編譯辨泳、鏈接、匯編輸出的文件成為目標(biāo)文件(Object File)

- 鏈接

鏈接的主要內(nèi)容就是把各個(gè)模塊之間相互引用的部分處理好玖院,使各個(gè)模塊可以正確的拼接菠红。
鏈接的主要過程包塊 地址和空間的分配(Address and Storage Allocation)、符號(hào)決議(Symbol Resolution)和重定位(Relocation)等步驟难菌。

- 靜態(tài)鏈接和動(dòng)態(tài)鏈接

靜態(tài)鏈接方法:靜態(tài)鏈接的時(shí)候试溯,載入代碼就會(huì)把程序會(huì)用到的動(dòng)態(tài)代碼或動(dòng)態(tài)代碼的地址確定下來
靜態(tài)庫(kù)的鏈接可以使用靜態(tài)鏈接,動(dòng)態(tài)鏈接庫(kù)也可以使用這種方法鏈接導(dǎo)入庫(kù)

動(dòng)態(tài)鏈接方法:使用這種方式的程序并不在一開始就完成動(dòng)態(tài)鏈接郊酒,而是直到真正調(diào)用動(dòng)態(tài)庫(kù)代碼時(shí)遇绞,載入程序才計(jì)算(被調(diào)用的那部分)動(dòng)態(tài)代碼的邏輯地址,然后等到某個(gè)時(shí)候燎窘,程序又需要調(diào)用另外某塊動(dòng)態(tài)代碼時(shí)摹闽,載入程序又去計(jì)算這部分代碼的邏輯地址,所以褐健,這種方式使程序初始化時(shí)間較短钩骇,但運(yùn)行期間的性能比不上靜態(tài)鏈接的程序

- 虛擬內(nèi)存技術(shù)

虛擬存儲(chǔ)器是值具有請(qǐng)求調(diào)入功能和置換功能,能從邏輯上對(duì)內(nèi)存容量加以擴(kuò)充的一種存儲(chǔ)系統(tǒng).

- 分頁和分段

分頁: 用戶程序的地址空間被劃分成若干固定大小的區(qū)域,稱為“頁”,相應(yīng)地倘屹,內(nèi)存空間分成若干個(gè)物理塊,頁和塊的大小相等慢叨∨Τ祝可將用戶程序的任一頁放在內(nèi)存的任一塊中,實(shí)現(xiàn)了離散分配拍谐。

分段: 將用戶程序地址空間分成若干個(gè)大小不等的段烛缔,每段可以定義一組相對(duì)完整的邏輯信息。存儲(chǔ)分配時(shí)轩拨,以段為單位践瓷,段與段在內(nèi)存中可以不相鄰接,也實(shí)現(xiàn)了離散分配亡蓉。

分頁與分段的主要區(qū)別

頁是信息的物理單位,分頁是為了實(shí)現(xiàn)非連續(xù)分配,以便解決內(nèi)存碎片問題,或者說分頁是由于系統(tǒng)管理的需要.段是信息的邏輯單位,它含有一組意義相對(duì)完整的信息,分段的目的是為了更好地實(shí)現(xiàn)共享,滿足用戶的需要.
頁的大小固定,由系統(tǒng)確定,將邏輯地址劃分為頁號(hào)和頁內(nèi)地址是由機(jī)器硬件實(shí)現(xiàn)的.而段的長(zhǎng)度卻不固定,決定于用戶所編寫的程序,通常由編譯程序在對(duì)源程序進(jìn)行編譯時(shí)根據(jù)信息的性質(zhì)來劃分.
分頁的作業(yè)地址空間是一維的.分段的地址空間是二維的.

- 頁面置換算法

最佳置換算法OPT:不可能實(shí)現(xiàn)
先進(jìn)先出FIFO
最近最久未使用算法LRU:最近一段時(shí)間里最久沒有使用過的頁面予以置換.
clock算法

- 邊沿觸發(fā)和水平觸發(fā)

邊緣觸發(fā)是指每當(dāng)狀態(tài)變化時(shí)發(fā)生一個(gè) io 事件晕翠,條件觸發(fā)是只要滿足條件就發(fā)生一個(gè) io 事件

# 數(shù)據(jù)庫(kù)
## 事物
數(shù)據(jù)庫(kù)事務(wù)(Database Transaction) ,是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作砍濒,要么完全地執(zhí)行淋肾,要么完全地不執(zhí)行。
## 數(shù)據(jù)庫(kù)索引
推薦: http://tech.meituan.com/mysql-index.html

MySQL索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理(http://blog.jobbole.com/24006/)

聚集索引,非聚集索引,B-Tree,B+Tree,最左前綴原理
## Redis原理
## 樂觀鎖和悲觀鎖
悲觀鎖:假定會(huì)發(fā)生并發(fā)沖突爸邢,屏蔽一切可能違反數(shù)據(jù)完整性的操作

樂觀鎖:假設(shè)不會(huì)發(fā)生并發(fā)沖突樊卓,只在提交操作時(shí)檢查是否違反數(shù)據(jù)完整性。
## MVCC
## MyISAM和InnoDB
MyISAM 適合于一些需要大量查詢的應(yīng)用杠河,但其對(duì)于有大量寫操作并不是很好碌尔。甚至你只是需要update一個(gè)字段,整個(gè)表都會(huì)被鎖起來券敌,而別的進(jìn)程唾戚,就算是讀進(jìn)程都無法操作直到讀操作完成。另外陪白,MyISAM 對(duì)于 SELECT COUNT(*) 這類的計(jì)算是超快無比的颈走。

InnoDB 的趨勢(shì)會(huì)是一個(gè)非常復(fù)雜的存儲(chǔ)引擎,對(duì)于一些小的應(yīng)用咱士,它會(huì)比 MyISAM 還慢立由。他是它支持“行鎖” ,于是在寫操作比較多的時(shí)候序厉,會(huì)更優(yōu)秀锐膜。并且,他還支持更多的高級(jí)應(yīng)用弛房,比如:事務(wù)道盏。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荷逞,更是在濱河造成了極大的恐慌媒咳,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件种远,死亡現(xiàn)場(chǎng)離奇詭異涩澡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)坠敷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門妙同,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膝迎,你說我怎么就攤上這事粥帚。” “怎么了限次?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵芒涡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我掂恕,道長(zhǎng)拖陆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任懊亡,我火速辦了婚禮依啰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘店枣。我一直安慰自己速警,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布鸯两。 她就那樣靜靜地躺著闷旧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钧唐。 梳的紋絲不亂的頭發(fā)上忙灼,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音钝侠,去河邊找鬼该园。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帅韧,可吹牛的內(nèi)容都是我干的里初。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼忽舟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼双妨!你這毒婦竟也來了淮阐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤刁品,失蹤者是張志新(化名)和其女友劉穎泣特,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挑随,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡群扶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镀裤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缴饭,死狀恐怖暑劝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颗搂,我是刑警寧澤担猛,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站丢氢,受9級(jí)特大地震影響傅联,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疚察,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一蒸走、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧貌嫡,春花似錦比驻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至夫椭,卻和暖如春掸掸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹭秋。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工扰付, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人感凤。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓悯周,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親陪竿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子禽翼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容