package p2p
10年積累的成都做網(wǎng)站、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有石嘴山免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
import (
"context"
"errors"
"time"
net "gx/ipfs/QmPjvxTpVH8qJyQDnxnsxF9kv9jezKD1kozz1hs3fCGsNh/go-libp2p-net"
manet "gx/ipfs/QmV6FjemM1K8oXjrvuq3wuVWWoU2TLDPmNnKrxHzY3v6Ai/go-multiaddr-net"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
pro "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
pstore "gx/ipfs/QmZR2XWVVBCtbgBWnQhWk2xcQfaR3W8faQPriAiaaj7rsr/go-libp2p-peerstore"
p2phost "gx/ipfs/Qmb8T6YBBsjYsVGfrihQLfCJveczZnneSBqBKkYEBWDjge/go-libp2p-host"
peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer"
)
//P2P結(jié)構(gòu)保存當(dāng)前正在運(yùn)行的流/監(jiān)聽器的信息
// P2P structure holds information on currently running streams/listeners
type P2P struct {
//監(jiān)聽器
Listeners ListenerRegistry
//數(shù)據(jù)流
Streams StreamRegistry
//節(jié)點(diǎn)ID
identity peer.ID
//節(jié)點(diǎn)地址
peerHost p2phost.Host
//一個(gè)線程安全的對等節(jié)點(diǎn)存儲
peerstore pstore.Peerstore
}
//創(chuàng)建一個(gè)新的p2p結(jié)構(gòu)
// NewP2P creates new P2P struct
//這個(gè)新的p2p結(jié)構(gòu)不包含p2p結(jié)構(gòu)中的監(jiān)聽器和數(shù)據(jù)流
func NewP2P(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore) *P2P {
return P2P{
identity: identity,
peerHost: peerHost,
peerstore: peerstore,
}
}
//新建一個(gè)數(shù)據(jù)流 工具方法 構(gòu)建一個(gè)有節(jié)點(diǎn)id,內(nèi)容和協(xié)議的流
func (p2p P2P) newStreamTo(ctx2 context.Context, p peer.ID, protocol string) (net.Stream, error) {
//30s 后會自動timeout
ctx, cancel := context.WithTimeout(ctx2, time.Second 30) //TODO: configurable?
defer cancel()
err := p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: p})
if err != nil {
return nil, err
}
return p2p.peerHost.NewStream(ctx2, p, pro.ID(protocol))
}
//對話為遠(yuǎn)程監(jiān)聽器創(chuàng)建新的P2P流
//創(chuàng)建一個(gè)新的p2p流實(shí)現(xiàn)對對話的監(jiān)聽
// Dial creates new P2P stream to a remote listener
//Multiaddr是一種跨協(xié)議、跨平臺的表示格式的互聯(lián)網(wǎng)地址。它強(qiáng)調(diào)明確性和自我描述。
//對內(nèi)接收
func (p2p P2P) Dial(ctx context.Context, addr ma.Multiaddr, peer peer.ID, proto string, bindAddr ma.Multiaddr) ( ListenerInfo, error) {
//獲取一些節(jié)點(diǎn)信息 network, host, nil
lnet, _, err := manet.DialArgs(bindAddr)
if err != nil {
return nil, err
}
//監(jiān)聽信息
listenerInfo := ListenerInfo{
//節(jié)點(diǎn)身份
Identity: p2p.identity,
////應(yīng)用程序協(xié)議標(biāo)識符。
Protocol: proto,
}
//調(diào)用newStreamTo 通過ctx(內(nèi)容) peer(節(jié)點(diǎn)id) proto(協(xié)議標(biāo)識符) 參數(shù)獲取一個(gè)新的數(shù)據(jù)流
remote, err := p2p.newStreamTo(ctx, peer, proto)
if err != nil {
return nil, err
}
//network協(xié)議標(biāo)識
switch lnet {
//network為"tcp", "tcp4", "tcp6"
case "tcp", "tcp4", "tcp6":
//從監(jiān)聽器獲取新的信息 nla.Listener, nil
listener, err := manet.Listen(bindAddr)
if err != nil {
if err2 := remote.Reset(); err2 != nil {
return nil, err2
}
return nil, err
}
//將獲取的新信息保存到listenerInfo
listenerInfo.Address = listener.Multiaddr()
listenerInfo.Closer = listener
listenerInfo.Running = true
//開啟接受
go p2p.doAccept(listenerInfo, remote, listener)
default:
return nil, errors.New("unsupported protocol: " + lnet)
}
return listenerInfo, nil
}
//
func (p2p *P2P) doAccept(listenerInfo *ListenerInfo, remote net.Stream, listener manet.Listener) {
//關(guān)閉偵聽器并刪除流處理程序
defer listener.Close()
//Returns a Multiaddr friendly Conn
//一個(gè)有好的 Multiaddr 連接
local, err := listener.Accept()
if err != nil {
return
}
stream := StreamInfo{
//連接協(xié)議
Protocol: listenerInfo.Protocol,
//定位節(jié)點(diǎn)
LocalPeer: listenerInfo.Identity,
//定位節(jié)點(diǎn)地址
LocalAddr: listenerInfo.Address,
//遠(yuǎn)程節(jié)點(diǎn)
RemotePeer: remote.Conn().RemotePeer(),
//遠(yuǎn)程節(jié)點(diǎn)地址
RemoteAddr: remote.Conn().RemoteMultiaddr(),
//定位
Local: local,
//遠(yuǎn)程
Remote: remote,
//注冊碼
Registry: p2p.Streams,
}
//注冊連接信息
p2p.Streams.Register(stream)
//開啟節(jié)點(diǎn)廣播
stream.startStreaming()
}
//偵聽器將流處理程序包裝到偵聽器中
// Listener wraps stream handler into a listener
type Listener interface {
Accept() (net.Stream, error)
Close() error
}
//P2PListener保存關(guān)于偵聽器的信息
// P2PListener holds information on a listener
type P2PListener struct {
peerHost p2phost.Host
conCh chan net.Stream
proto pro.ID
ctx context.Context
cancel func()
}
//等待偵聽器的連接
// Accept waits for a connection from the listener
func (il *P2PListener) Accept() (net.Stream, error) {
select {
case c := -il.conCh:
return c, nil
case -il.ctx.Done():
return nil, il.ctx.Err()
}
}
//關(guān)閉偵聽器并刪除流處理程序
// Close closes the listener and removes stream handler
func (il *P2PListener) Close() error {
il.cancel()
il.peerHost.RemoveStreamHandler(il.proto)
return nil
}
// Listen創(chuàng)建新的P2PListener
// Listen creates new P2PListener
func (p2p P2P) registerStreamHandler(ctx2 context.Context, protocol string) ( P2PListener, error) {
ctx, cancel := context.WithCancel(ctx2)
list := P2PListener{
peerHost: p2p.peerHost,
proto: pro.ID(protocol),
conCh: make(chan net.Stream),
ctx: ctx,
cancel: cancel,
}
p2p.peerHost.SetStreamHandler(list.proto, func(s net.Stream) {
select {
case list.conCh - s:
case -ctx.Done():
s.Reset()
}
})
return list, nil
}
// NewListener創(chuàng)建新的p2p偵聽器
// NewListener creates new p2p listener
//對外廣播
func (p2p P2P) NewListener(ctx context.Context, proto string, addr ma.Multiaddr) ( ListenerInfo, error) {
//調(diào)用registerStreamHandler 構(gòu)造一個(gè)新的listener
listener, err := p2p.registerStreamHandler(ctx, proto)
if err != nil {
return nil, err
}
//構(gòu)造新的listenerInfo
listenerInfo := ListenerInfo{
Identity: p2p.identity,
Protocol: proto,
Address: addr,
Closer: listener,
Running: true,
Registry: p2p.Listeners,
}
go p2p.acceptStreams(listenerInfo, listener)
//注冊連接信息
p2p.Listeners.Register(listenerInfo)
return listenerInfo, nil
}
//接受流
func (p2p *P2P) acceptStreams(listenerInfo *ListenerInfo, listener Listener) {
for listenerInfo.Running {
//一個(gè)有好的 遠(yuǎn)程 連接
remote, err := listener.Accept()
if err != nil {
listener.Close()
break
}
}
//取消注冊表中的p2p偵聽器
p2p.Listeners.Deregister(listenerInfo.Protocol)
}
// CheckProtoExists檢查是否注冊了協(xié)議處理程序
// mux處理程序
// CheckProtoExists checks whether a protocol handler is registered to
// mux handler
func (p2p *P2P) CheckProtoExists(proto string) bool {
protos := p2p.peerHost.Mux().Protocols()
for _, p := range protos {
if p != proto {
continue
}
return true
}
return false
}
1.找淺顯易懂,例程比較好的教程,從頭到尾看下去。不要看很多本,專注于一本。把里面的例程都手打一遍,搞懂為什么。
2.去找實(shí)際項(xiàng)目練手。最好是要有真實(shí)的項(xiàng)目做??梢哉?guī)讉€(gè)同學(xué)一起做個(gè)網(wǎng)站之類。注意,真實(shí)項(xiàng)目不一定非要是商業(yè)項(xiàng)目。
3.最好能找到一個(gè)已經(jīng)會python的人。問他一點(diǎn)學(xué)習(xí)規(guī)劃的建議,然后在遇到卡殼的地方找他指點(diǎn)。這樣會事半功倍。
4.另外,除了學(xué)習(xí)編程語言,也兼顧補(bǔ)一點(diǎn)計(jì)算機(jī)基礎(chǔ),和英語。
5.不但要學(xué)寫代碼,還要學(xué)會看代碼,更要會調(diào)試代碼。讀懂你自己程序的報(bào)錯信息。再去找些github上的程序,讀懂別人的代碼。
6.學(xué)會查文檔,用好搜索引擎和開發(fā)者社區(qū)。
想學(xué)Python的童鞋可以加企鵝裙前三位是227,中間是435,后三位是450分享軟件視頻資料
學(xué)Python和學(xué)其他的語言其實(shí)是相同的,我給新同事講課的時(shí)候就說學(xué)編程和練武功其實(shí)是很相似,入門大致這樣幾步:
找本靠譜的書,
找個(gè)靠譜的師傅,
找一個(gè)地方開始練習(xí)。
學(xué)語言也是的:選一本通俗易懂的書,找一個(gè)好的視頻資料,然后自己裝一個(gè)IDE工具開始邊學(xué)變寫。下面我具體來講講:
1.找一本靠譜的書,難度一定要是入門級別,千萬不能太復(fù)雜,不要一下子陷進(jìn)去,會打亂節(jié)奏,學(xué)東西要循序漸進(jìn),不能一口吃個(gè)胖子.打個(gè)比方,學(xué)過java的同學(xué)都聽過大名鼎鼎的thinking in java,這邊書很厚很全,若一上來就學(xué),肯定會吃力,時(shí)間長了就會失去興趣,因此對初學(xué)者來說,一定要找一個(gè)通熟易懂的,簡單的書。入門的書非常關(guān)鍵。
入門的書很多,但是我個(gè)人強(qiáng)烈推薦"A Byte of Python",這本書我讀了2遍,作者寫的思路非常清晰,對每一個(gè)知識點(diǎn)講解的很到位,不多不少,剛剛好,對初學(xué)者來說,力道剛剛好。而且是全英文,對提高自己的英語水平,很有幫助.
網(wǎng)上有人會推薦"笨辦法學(xué)Python",我個(gè)人覺得這本書沒有"A Byte of Python"好 .一般有一些編程基本,我建議直接看"A Byte of Python".這本書的銷量已經(jīng)破百萬了,而且在豆瓣上點(diǎn)評有8.8,可謂是入門級的神書.電子版大家可以在CSDN 搜一下就有,都是高清的.
2.多編寫程序,這似乎是廢話,但是確實(shí)是一句實(shí)話。學(xué)編程一定要親身去編寫,沒有什么捷徑.一開始哪怕你把書里面的例子一字不落敲一遍,也好過你只是去看書,而不動手。
而且學(xué)python 最好是堅(jiān)持編,每天抽小半個(gè)小時(shí),學(xué)一些知識點(diǎn),不斷的堅(jiān)持.大概快的話幾個(gè)星期基本就能入門了。
以上就是我對python 入門的感悟,希望對初學(xué)者能有一點(diǎn)幫助,能幫到一些人少走一點(diǎn)彎路.也就不枉我大半夜在這里碼字了~~
最后說一下,我堅(jiān)持原創(chuàng),若我寫的對大家有幫助,麻煩大家支持一下,也是對我的一點(diǎn)鼓勵和動力。
當(dāng)然,如果你是0基礎(chǔ),周圍也沒有大神帶領(lǐng),自己也學(xué)不進(jìn)去,我勸你還是放棄吧,或者就找個(gè)培訓(xùn)機(jī)構(gòu)花點(diǎn)錢學(xué)習(xí)
謝謝
繼續(xù)進(jìn)入下一個(gè)初始化
n.netService, err = nebnet.NewNebService(n)
if err != nil {
logging.CLog().WithFields(logrus.Fields{
"err": err,
}).Fatal("Failed to setup net service.")
}
netservice有兩個(gè)成員
type NebServicestruct {
node? ? ? *Node
dispatcher *Dispatcher
}
跳出stup()函數(shù)
先進(jìn)入start()函數(shù)看一看
if err := n.netService.Start(); err != nil {
logging.CLog().WithFields(logrus.Fields{
"err": err,
}).Fatal("Failed to start net service.")
}
進(jìn)入netservice.start()
func (ns *NebService) Start() error {
logging.CLog().Info("Starting NebService...")
// start dispatcher.
ns.dispatcher.Start()
// start node.
if err := ns.node.Start(); err != nil {
ns.dispatcher.Stop()
logging.CLog().WithFields(logrus.Fields{
"err": err,
}).Error("Failed to start NebService.")
return err
}
logging.CLog().Info("Started NebService.")
return nil
}
可以看到第一個(gè)start()的函數(shù)是dispatcher.start()
進(jìn)入dispatch.start()
func (dp *Dispatcher) Start() {
logging.CLog().Info("Starting NebService Dispatcher...")
go dp.loop()
}
然后就出現(xiàn)一個(gè)新的線程、goruntime
go dp.loop()
進(jìn)入該線程,看它干了些什么
timerChan := time.NewTicker(time.Second).C
for {
select {
case -timerChan:
metricsDispatcherCached.Update(int64(len(dp.receivedMessageCh)))
case -dp.quitCh:
logging.CLog().Info("Stoped NebService Dispatcher.")
return
case msg := -dp.receivedMessageCh:
msgType := msg.MessageType()
v, _ := dp.subscribersMap.Load(msgType)
if v == nil {
continue
? }
m, _ := v.(*sync.Map)
m.Range(func(key, valueinterface{}) bool {
select {
case key.(*Subscriber).msgChan - msg:
default:
logging.VLog().WithFields(logrus.Fields{
"msgType": msgType,
}).Warn("timeout to dispatch message.")
}
return true
? })
}
}
一個(gè)有點(diǎn)長的循環(huán)
metricsDispatcherCached.Update(int64(len(dp.receivedMessageCh)))一秒鐘刷新一次緩沖區(qū)
case msg := -dp.receivedMessageCh:
msgType := msg.MessageType()如果能取出dp.receivedMessageCh
msgType := msg.MessageType()首先判斷取出的信息類型
v, _ := dp.subscribersMap.Load(msgType)
if v == nil {
continue
}
根據(jù)類型取出相應(yīng)的map
如果取不出,那么使用continue結(jié)束這個(gè)case
m, _ := v.(*sync.Map)
斷言
m.Range(func(key, valueinterface{}) bool {
select {
case key.(*Subscriber).msgChan - msg:
default:
logging.VLog().WithFields(logrus.Fields{
"msgType": msgType,
}).Warn("timeout to dispa+tch message.")
}
return true
})
將msg推入其他管道里面去。其他goruntime會循環(huán)等待該
任何一門計(jì)算機(jī)語言,都能在特定某個(gè)領(lǐng)域的應(yīng)用中,實(shí)現(xiàn)區(qū)塊鏈技術(shù);
具體使用哪一門語言,完全看我們相應(yīng)領(lǐng)域行業(yè)企業(yè)項(xiàng)目的技術(shù)要求,以及更關(guān)鍵的:跟已有信息系統(tǒng)的有效對接聯(lián)通。
區(qū)塊鏈具有自下而上生成記錄,生成兩方或多方合同類記錄,加入第三方確認(rèn)機(jī)制,分布存儲,……等特點(diǎn);
從而讓它相比集中式的存儲運(yùn)算而言,變得更為可信。
常見的總統(tǒng)投票,就非常適合以區(qū)塊鏈技術(shù)重新架構(gòu);采用區(qū)塊鏈技術(shù)的投票系統(tǒng),能夠避免哪一家技術(shù)公司、某一個(gè)關(guān)鍵技術(shù)人員,操縱選票統(tǒng)計(jì)結(jié)果的可能。
像我們的法院證據(jù),也特別適合采用區(qū)塊鏈技術(shù)重新架構(gòu)開發(fā)。
其實(shí)像當(dāng)前我們各類互聯(lián)網(wǎng)時(shí)代的“版權(quán)系統(tǒng)”,它們中一些就是采用區(qū)塊鏈技術(shù)架構(gòu)而來,只不過,目前我們的新聞出版局、專利局(或者更廣義地被稱作“專家評委”),都尚未接入這些由互聯(lián)網(wǎng)公司創(chuàng)新而來的版權(quán)平臺。
我們耳熟能詳 的“法大大”(雖然名字不甚好聽、甚至乍一聽來有些讓人“摸不著頭腦”),它也其實(shí)正準(zhǔn)備采用最新的區(qū)塊鏈技術(shù)重新架構(gòu);采用區(qū)塊鏈技術(shù)的合同平臺,因?yàn)樽兊酶涌尚?,也才能更便于互?lián)網(wǎng)時(shí)代人們簽訂各類商務(wù)合同。
還有像我們的“征信系統(tǒng)”,也非常適合以區(qū)塊鏈技術(shù)加以改造。能夠讓它更有說服力,而不致于出現(xiàn)一家單位、乃至隨意某個(gè)關(guān)鍵技術(shù)人員,能隨意往其中添加“征信污點(diǎn)數(shù)據(jù)”的情況。
還有像我們的P2P貸款,如果能夠以區(qū)塊鏈技術(shù)重新架構(gòu)的話,也能夠變得更加可信,而不致于出現(xiàn)違約、卷款跑路這樣的失信情況。
相信在IT領(lǐng)域發(fā)展的同學(xué)對Java很熟悉。Java編程語言排行中一直處于領(lǐng)先地位,這可以直接體現(xiàn)Java的重要。因此很多同學(xué)準(zhǔn)備參加Python培訓(xùn)機(jī)構(gòu)系統(tǒng)學(xué)習(xí)。那么,Python培訓(xùn)機(jī)構(gòu)哪家比較好?下面我們介紹一下。
隨著Java的普及,越來越多的人了解Java,企業(yè)也會對求職者提出更高的要求,他們想招聘一些能馬上開始工作的人,所以往往會招聘一些有項(xiàng)目開發(fā)經(jīng)驗(yàn)的人。這就是為什么那么多計(jì)算機(jī)專業(yè)的大學(xué)生找不到工作,所以越來越多的大學(xué)生會選擇在畢業(yè)前后參加一些專業(yè)的Python培訓(xùn)課程,以增加他們的實(shí)踐經(jīng)驗(yàn)。只有增強(qiáng)自己的力量,才能立于不敗之地。
Python培訓(xùn)機(jī)構(gòu)哪家比較好?判斷Python培訓(xùn)機(jī)構(gòu)好與壞主要看以下幾個(gè)方面
1.看教學(xué)課程內(nèi)容
學(xué)習(xí)Java技術(shù),最主要是與時(shí)俱進(jìn),掌握的技術(shù)點(diǎn)能夠滿足時(shí)下企業(yè)的用人需求。而想要了解一家培訓(xùn)機(jī)構(gòu)所提供的課程是否新穎,也可以去機(jī)構(gòu)的官網(wǎng)上看看,了解自己想學(xué)習(xí)的學(xué)科的課程大綱。看看學(xué)習(xí)路線圖是如何安排的,有沒有從零到一的系統(tǒng)搭建,是不是有強(qiáng)化實(shí)訓(xùn)、實(shí)操的比重,有盡量多的項(xiàng)目實(shí)戰(zhàn)。因?yàn)槠髽I(yè)對Java從業(yè)者的技術(shù)能力和動手實(shí)戰(zhàn)能力要求較高。
2.看師資力量
因?yàn)镴ava開發(fā)技術(shù)知識的專業(yè)性很強(qiáng),如果盲目去學(xué)很容易走進(jìn)誤區(qū)。相反,有講師帶領(lǐng),站在巨人的肩膀上,往往事半功倍。畢竟現(xiàn)在這個(gè)時(shí)代只要多跟別人交流才能獲得更多更有價(jià)值的信息,初學(xué)者千萬不能閉門造車。
3.看口碑
行業(yè)內(nèi)口碑比較好,學(xué)生對培訓(xùn)機(jī)構(gòu)比較認(rèn)可,這種機(jī)構(gòu)把精力放在了學(xué)生身上的機(jī)構(gòu),才是做教育的應(yīng)有態(tài)度。
4.看就業(yè)情況
以學(xué)生就業(yè)為目標(biāo)的培訓(xùn)機(jī)構(gòu)現(xiàn)在才是最主要的。要知道就業(yè)也是教學(xué)成果的體現(xiàn),沒有好的教學(xué)保證是做不到好的就業(yè)的。
5.上門免費(fèi)試聽
試聽是為了更好的去感受培訓(xùn)機(jī)構(gòu)的課程內(nèi)容、講課風(fēng)格、班級氛圍等,同時(shí)也能通過和班上在讀同學(xué)進(jìn)行交流,更進(jìn)一步去了解這家培訓(xùn)機(jī)構(gòu)各個(gè)方面是否符合自己的需要。
是否非常想學(xué)好 Python,一方面被瑣事糾纏,一直沒能動手,另一方面,擔(dān)心學(xué)習(xí)成本太高,心里默默敲著退堂鼓?
幸運(yùn)的是,Python 是一門初學(xué)者友好的編程語言,想要完全掌握它,你不必花上太多的時(shí)間和精力。
Python 的設(shè)計(jì)哲學(xué)之一就是簡單易學(xué),體現(xiàn)在兩個(gè)方面:
語法簡潔明了:相對 Ruby 和 Perl,它的語法特性不多不少,大多數(shù)都很簡單直接,不玩兒玄學(xué)。
切入點(diǎn)很多:Python 可以讓你可以做很多事情,科學(xué)計(jì)算和數(shù)據(jù)分析、爬蟲、Web 網(wǎng)站、游戲、命令行實(shí)用工具等等等等,總有一個(gè)是你感興趣并且愿意投入時(shí)間的。
廢話不多說,學(xué)會一門語言的捷徑只有一個(gè): Getting Started
? 起步階段
任何一種編程語言都包含兩個(gè)部分:硬知識和軟知識,起步階段的主要任務(wù)是掌握硬知識。
硬知識
“硬知識”指的是編程語言的語法、算法和數(shù)據(jù)結(jié)構(gòu)、編程范式等,例如:變量和類型、循環(huán)語句、分支、函數(shù)、類。這部分知識也是具有普適性的,看上去是掌握了一種語法,實(shí)際是建立了一種思維。例如:讓一個(gè) Java 程序員去學(xué)習(xí) Python,他可以很快的將 Java 中的學(xué)到的面向?qū)ο蟮闹R map 到 Python 中來,因此能夠快速掌握 Python 中面向?qū)ο蟮奶匦浴?/p>
如果你是剛開始學(xué)習(xí)編程的新手,一本可靠的語法書是非常重要的。它看上去可能非??菰锓ξ?,但對于建立穩(wěn)固的編程思維是必不可少。
下面列出了一些適合初學(xué)者入門的教學(xué)材料:
廖雪峰的 Python 教程 ? ?Python 中文教程的翹楚,專為剛剛步入程序世界的小白打造。 ?
笨方法學(xué) Python ? ?這本書在講解 Python 的語法成分時(shí),還附帶大量可實(shí)踐的例子,非常適合快速起步。 ?
The Hitchhiker’s Guide to Python! ? ?這本指南著重于 Python 的最佳實(shí)踐,不管你是 Python 專家還是新手,都能獲得極大的幫助。 ?
Python 的哲學(xué):
用一種方法,最好是只有一種方法來做一件事。
學(xué)習(xí)也是一樣,雖然推薦了多種學(xué)習(xí)資料,但實(shí)際學(xué)習(xí)的時(shí)候,最好只選擇其中的一個(gè),堅(jiān)持看完。
必要的時(shí)候,可能需要閱讀講解數(shù)據(jù)結(jié)構(gòu)和算法的書,這些知識對于理解和使用 Python 中的對象模型有著很大的幫助。
軟知識
“軟知識”則是特定語言環(huán)境下的語法技巧、類庫的使用、IDE的選擇等等。這一部分,即使完全不了解不會使用,也不會妨礙你去編程,只不過寫出的程序,看上去顯得“傻”了些。
對這些知識的學(xué)習(xí),取決于你嘗試解決的問題的領(lǐng)域和深度。對初學(xué)者而言,起步階段極易走火,或者在選擇 Python 版本時(shí)徘徊不決,一會兒看 2.7 一會兒又轉(zhuǎn)到 3.0,或者徜徉在類庫的大海中無法自拔,Scrapy,Numpy,Django 什么都要試試,或者參與編輯器圣戰(zhàn)、大括號縮進(jìn)探究、操作系統(tǒng)辯論賽等無意義活動,或者整天跪舔語法糖,老想著怎么一行代碼把所有的事情做完,或者去構(gòu)想圣潔的性能安全通用性健壯性全部滿分的解決方案。
很多“大?!倍紩嬲]初學(xué)者,用這個(gè)用那個(gè),少走彎路,這樣反而把初學(xué)者推向了真正的彎路。
還不如告訴初學(xué)者,學(xué)習(xí)本來就是個(gè)需要你去走彎路出 Bug,只能腳踏實(shí)地,沒有奇跡只有狗屎的過程。
選擇一個(gè)方向先走下去,哪怕臟丑差,走不動了再看看有沒有更好的解決途徑。
自己走了彎路,你才知道這么做的好處,才能理解為什么人們可以手寫狀態(tài)機(jī)去匹配卻偏要發(fā)明正則表達(dá)式,為什么面向過程可以解決卻偏要面向?qū)ο螅瑸槭裁次铱梢圆倏v每一根指針卻偏要自動管理內(nèi)存,為什么我可以嵌套回調(diào)卻偏要用 Promise...
更重要的是,你會明白,高層次的解決方法都是對低層次的封裝,并不是任何情況下都是最有效最合適的。
技術(shù)涌進(jìn)就像波浪一樣,那些陳舊的封存已久的技術(shù),消退了遲早還會涌回的。就像現(xiàn)在移動端應(yīng)用、手游和 HTML5 的火熱,某些方面不正在重演過去 PC 的那些歷史么?
因此,不要擔(dān)心自己走錯路誤了終身,堅(jiān)持并保持進(jìn)步才是正道。
起步階段的核心任務(wù)是掌握硬知識,軟知識做適當(dāng)了解,有了穩(wěn)固的根,粗壯的枝干,才能長出濃密的葉子,結(jié)出甜美的果實(shí)。
? 發(fā)展階段
完成了基礎(chǔ)知識的學(xué)習(xí),必定會感到一陣空虛,懷疑這些語法知識是不是真的有用。
沒錯,你的懷疑是非常正確的。要讓 Python 發(fā)揮出它的價(jià)值,當(dāng)然不能停留在語法層面。
發(fā)展階段的核心任務(wù),就是“跳出 Python,擁抱世界”。
在你面前會有多個(gè)分支:科學(xué)計(jì)算和數(shù)據(jù)分析、爬蟲、Web 網(wǎng)站、游戲、命令行實(shí)用工具等等等等,這些都不是僅僅知道 Python 語法就能解決的問題。
拿爬蟲舉例,如果你對計(jì)算機(jī)網(wǎng)絡(luò),HTTP 協(xié)議,HTML,文本編碼,JSON 一無所知,你能做好這部分的工作么?而你在起步階段的基礎(chǔ)知識也同樣重要,如果你連循環(huán)遞歸怎么寫都還要查文檔,連 BFS 都不知道怎么實(shí)現(xiàn),這就像工匠做石凳每次起錘都要思考錘子怎么使用一樣,非常低效。
在這個(gè)階段,不可避免要接觸大量類庫,閱讀大量書籍的。
類庫方面
「Awesome Python 項(xiàng)目」:vinta/awesome-python · GitHub
這里列出了你在嘗試解決各種實(shí)際問題時(shí),Python 社區(qū)已有的工具型類庫,如下圖所示:
請點(diǎn)擊輸入圖片描述
vinta/awesome-python
你可以按照實(shí)際需求,尋找你需要的類庫。
至于相關(guān)類庫如何使用,必須掌握的技能便是閱讀文檔。由于開源社區(qū)大多數(shù)文檔都是英文寫成的,所以,英語不好的同學(xué),需要惡補(bǔ)下。
書籍方面
這里我只列出一些我覺得比較有一些幫助的書籍,詳細(xì)的請看豆瓣的書評:
科學(xué)和數(shù)據(jù)分析:
?「集體智慧編程」:集體智慧編程 (豆瓣)
?「數(shù)學(xué)之美」:數(shù)學(xué)之美 (豆瓣)
?「統(tǒng)計(jì)學(xué)習(xí)方法」:統(tǒng)計(jì)學(xué)習(xí)方法 (豆瓣)
?「Pattern Recognition And Machine Learning」:Pattern Recognition And Machine Learning (豆瓣)
?「數(shù)據(jù)科學(xué)實(shí)戰(zhàn)」:數(shù)據(jù)科學(xué)實(shí)戰(zhàn) (豆瓣)
?「數(shù)據(jù)檢索導(dǎo)論」:信息檢索導(dǎo)論 (豆瓣)
爬蟲:
?「HTTP 權(quán)威指南」:HTTP權(quán)威指南 (豆瓣)
Web 網(wǎng)站:
?「HTML CSS 設(shè)計(jì)與構(gòu)建網(wǎng)站」:HTML CSS設(shè)計(jì)與構(gòu)建網(wǎng)站 (豆瓣)
...
列到這里已經(jīng)不需要繼續(xù)了。
聰明的你一定會發(fā)現(xiàn)上面的大部分書籍,并不是講 Python 的書,而更多的是專業(yè)知識。
事實(shí)上,這里所謂“跳出 Python,擁抱世界”,其實(shí)是發(fā)現(xiàn) Python 和專業(yè)知識相結(jié)合,能夠解決很多實(shí)際問題。這個(gè)階段能走到什么程度,更多的取決于自己的專業(yè)知識。
? 深入階段
這個(gè)階段的你,對 Python 幾乎了如指掌,那么你一定知道 Python 是用 C 語言實(shí)現(xiàn)的。
可是 Python 對象的“動態(tài)特征”是怎么用相對底層,連自動內(nèi)存管理都沒有的C語言實(shí)現(xiàn)的呢?這時(shí)候就不能停留在表面了,勇敢的拆開 Python 的黑盒子,深入到語言的內(nèi)部,去看它的歷史,讀它的源碼,才能真正理解它的設(shè)計(jì)思路。
這里推薦一本書:
「Python 源碼剖析」:Python源碼剖析 (豆瓣)
這本書把 Python 源碼中最核心的部分,給出了詳細(xì)的闡釋,不過閱讀此書需要對 C 語言內(nèi)存模型和指針有著很好的理解。
另外,Python 本身是一門雜糅多種范式的動態(tài)語言,也就是說,相對于 C 的過程式、 Haskell 等的函數(shù)式、Java 基于類的面向?qū)ο蠖?,它都不夠純粹。換而言之,編程語言的“道學(xué)”,在 Python 中只能有限的體悟。學(xué)習(xí)某種編程范式時(shí),從那些面向這種范式更加純粹的語言出發(fā),才能有更深刻的理解,也能了解到 Python 語言的根源。
這里推薦一門公開課
「編程范式」:斯坦福大學(xué)公開課:編程范式
講師高屋建瓴,從各種編程范式的代表語言出發(fā),給出了每種編程范式最核心的思想。
值得一提的是,這門課程對C語言有非常深入的講解,例如C語言的范型和內(nèi)存管理。這些知識,對閱讀 Python 源碼也有大有幫助。
Python 的許多最佳實(shí)踐都隱藏在那些眾所周知的框架和類庫中,例如 Django、Tornado 等等。在它們的源代碼中淘金,也是個(gè)不錯的選擇。
? ?最后的話
每個(gè)人學(xué)編程的道路都是不一樣的,其實(shí)大都殊途同歸,沒有迷路的人只有不能堅(jiān)持的人!
希望想學(xué) Python 想學(xué)編程的同學(xué),不要猶豫了,看完這篇文章,
Just Getting Started ??。?!