主頁 >  其他 > 閉包還可以這樣寫?談談少兒編程工具的實作思路

閉包還可以這樣寫?談談少兒編程工具的實作思路

2020-09-29 06:14:26 其他

  著作權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖,如要轉貼,必須注明原文網址

  http://www.cnblogs.com/Colin-Cai/p/11601046.html 

  作者:窗戶

  QQ/微信:6679072

  E-mail:[email protected]

  詭異的代碼  

 

  

  看看這段代碼,很明顯,是列舉出100以內所有的質數,類似這樣的程式我們從學程式開始寫過很多,

  再仔細看看,這種“語言”似乎有點像我們學過的其他語言,但似乎并沒見過,語法有那么一點點古怪?!

  

 

  哦!看到了,原來是一段Python!

 

  

  上面代碼的執行結果是

  2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97

 

  再想想,這段程式本身就是一堆函陣列成,全都是Python的函式,而且全都作為run函式的引數,甚至引數的引數這樣呼叫執行,好詭異的代碼!如果想想這個如何實作的,怕是有點費腦子吧,

  

  面向程序的積木編程

  

  目前少兒編程很流行,世面上有很多平臺,最有名的要數Scratch,其他很多的少兒教育平臺大都是模仿Scratch的思路,

  

  上面是生成100以內質數的Scratch程式,在代碼堆里打滾的我們,即使從沒有見過Scratch,很快也會發現上述這樣的積木和我們的C語言、Python等常見的面向程序的程式看起來區別不是很大,于是,我們很快就可以使用Scratch進行編程,

  Scrach抽象出了變數、各種算術運算,抽象除了程序式(命令式)編程所用到的順序、回圈、條件分支;甚至于Scratch還可以造積木,這一定程度上模擬了函式的意義,而且積木還可以遞回;但Scratch下沒有break、continue,這在一定程度下使得程式更難編了一些,另外,Scratch甚至模擬了訊息(或者說信號)觸發這樣的抽象,目的可能是為了使編程更加有趣味性,

  

  理論上,積木編程當然也可以支持break、continue等,甚至可以goto,

 

  最普通的實作 

 

  本文不打算花太多篇幅來進行前端設計的描述,盡管是一個很復雜的話題,不過設計思路可以簡單的說一下,

  首先,我們為每一種積木建模,無論是Python還是JavaScript,我們都可以用class來描述,可以事先實作一個積木的基類,屬性里可以有積木的尺寸,圖片資訊等等,方法可以有包括圖片的加載,而具體的每一種積木則可以繼承于基類,當然,繼承里還可以再加一層,比如我們可以給積木分一個類,比如計算類、運行結構類、資料類、輸出類、輸入類……積木類里可能包含著其他的積木物件,比如對于運算來說,可能是別的兩個積木甚至更多的積木的參與,另外,每個積木也可以有一個resize或者reshape這樣的方法,因為形狀可能與它包含的其他積木物件是相關的,當然,還得需要move這樣的方法,

  其次,我們要為當前所有的積木建模,可以抽象出block(用來表示一段積木拼成的程式)和block_list(用來表示所有的block)這樣的類,block也有split/joint等方法,用于block的分裂、拼接,

  滑鼠拖動積木,可以對應于以上各種物件的操作,

  block_list里記錄了所有的積木,以及積木與積木之間的連接關系,其實這些關系對于語言編譯、解釋來說,正是第一步parser希望得到的結果,現在這些資訊雖然不是通過語言編譯得到,而是通過前端操作得到,但是資訊都完備了,那么可以直接使用這種連接關系一步一步得到最終的結果,這種方式應該是最正常的一種方式,

 

  使用開發語言

  

  于是,最簡單的實作可以是各個block映射成當前所用編程語言,再使用編程語言的eval函式來實作,很多語言都有eval函式,所以這個幾乎不是什么問題,

  比如假設我們的Scratch是用Python寫的,Scratch寫的質數程式可以挨個積木來翻譯,得到以下Python代碼:

var["i"] = 2
while not (var["i"]>10):
    var["k"] =  sqrt(var["i"])
    var["j"] = 2
    while not ((var["i"]>var["j"]) or ((var["i"]%var["j"])==0)):
        var["j"] += 1
    if (var["i"]>var["k"]):
        say(str(var["i"])+"是質數", 1)
    var["i"] += 1

 

  然后再在Python里實作該實作的函式即可,比如這里的say函式,

  以上的實作更為簡單直接,實際上的確世面上是有商業軟體是這么做的,特別是有的在線少兒編程教育,希望學生從積木編程過渡到具體計算機語言(一般還是Python、JavaScript)的學習,會給一個積木編程和具體計算機語言之間的對應,對于教育而言,這應該是一個挺不錯的想法,但是這個也有一定的問題,因為這種對應學習一般也會做語言到積木方向的映射,這個本身就要做對語言的parser,并且積木編程和具體語言編程很難做到完全合理的對應關系,特別是Python、JavaScript還支持面對物件、函式式編程,基本這些已經很難用積木的方式來表示了,

  再者,也不好教授單步、斷點這樣的除錯手段,而對于上一種的方式,卻很容易做到支持這些除錯方式,

 

  再造一種語言

 

  像上面一樣,還是依次把積木映射成字串,只是,不用原生的程式語言,而是再造一種語言,

  比如,上面的語言,可能被映射為以下這樣的形式:

 

until >(i,100)
 set(k,sqrt(i))
 set(j,2)
 until or(>(j,k),=(%(i,j),0))
  add(j,1)
 end
 if >(j,k)
  echo(concatent(i,"是質數"))
 end
 add(i,1)
end

  上面的形式看起來基本全是函式呼叫形式,雖然與普通的寫法不一樣,但是因為沒有了中綴運算式,語法決議全是函式,因為函式的表示非常簡單,基本上數括號就行,于是很容易區分函式名和各個引數,很明顯使用遞回很容易實作此處的函式呼叫,乃至自己寫一個堆疊來決議都很簡單,關鍵字此處只有until、if、end,從而可以很方便的做個解釋器,

  特別的,既然自己給出語言的解釋器,自然可以很容易的添加單步、斷點,

  當然,真的映射為帶中綴運算式的自然也可以,只是解釋器難度稍大一點罷了,

  Scratch采用的是另外一種相似的方式,它將所有的資料用json來封裝,而描述上述代碼格式的是用如下一段陣列,

[["whenGreenFlag"],
        ["setVar:to:", "i", "2"],
        ["doUntil",
                [">", ["readVariable", "i"], "100"],
                [["setVar:to:", "k", ["computeFunction:of:", "sqrt", ["readVariable", "i"]]],
                        ["setVar:to:", "j", "2"],
                ["doUntil",
                        ["|",
                        [">", ["readVariable", "j"], ["readVariable", "k"]],
                                ["=", ["%", ["readVariable", "i"], ["readVariable", "j"]], "0"]],
                        [["changeVar:by:", "j", 1]]],
                ["doIf",
                        [">", ["readVariable", "j"], ["readVariable", "k"]],
                        [["say:duration:elapsed:from:", ["concatenate:with:", ["readVariable", "i"], "是質數"], 1]]],
        ["changeVar:by:", "i", 1]]]]

  這段json的決議方式可以與上述全函式的方式高度一致,自然也是高度一致的處理手段,

  當然,我們也可以類似下面這樣使用中綴運算式

until i>100
 k=sqrt(i)
 j=2
 until j>k or i%j==0
  j+=1
 end
 if j>k
  echo(i,"是質數")
 end
 i+=1
end

  中綴運算式涉及到運算子的優先級問題,處理起來相對比較復雜一些,當然,我們也可以使用LEX/YACC來寫parser,這樣會方便很多,linux下LEX一般使用flex,YACC一般使用bison,不過既然這里的語言基本上只是做中間語言來使用,那么做成這樣基本是沒有必要,

 

圖計算

 

  細致的讀者應該可以想到,既然為圖形界面建模的程序中,所有的積木之間的關系已經是一個圖結構,而編程語言的編譯,目的就是為了把編程語言變換成圖結構,既然圖結構現在已經有了,生成中間代碼看上去不過是多轉了一道彎而已,那我們是不是可以利用這個圖結構直接計算呢?

  實際上,當然,我們是完全可以通過圖結構來做計算的,例如如下這樣的流程圖,我們的資料結構中蘊含著流程圖的每一條邊(圖是有向圖,從而邊有方向)以及節點意義,程式員顯然都有直接計算的直覺,

   

 

   資料結構示意大致如下:

  Node:

    A : i<=1

    B(Switch) : i<100

    C : 列印i

    D : i<=i+1

  Entrance:

     A

  Edge:

    A->B

    B(False)->C

    C->D

    D->A

    B(True)->End

 

內部DSL式建構

 

  所謂內部DSL,則是以宿主語言為基礎構建一種屬于自己的特定語言,這就意味著,新的語言實際上依然是宿主語言,只是在宿主語言基礎上構造了很多其他的限制東西,比如讓其看起來非常類似于完全獨立的語言,這是一種完全不同于前面設計的方法的設計,

  而我們也都知道,Lisp特別擅長干設計DSL的事情,特別是Scheme,有多種手段可以設計,比如我們可以用宏(Macro),Lisp的宏遠比C語言的宏要強大太多,雖說宏是文字替換,但Lisp的宏支持遞回,我們完全可以用Lisp的宏來做反復遞回替換,于是我們可以用非常靈活的方式替換我們的語法樹,甚至語法樹可以用宏被替換的“面目全非”,Scheme還有神一樣的continuation,大部分DSL可以設計為面向程序的方式,而continuation就可以很方便的為面向程序的流控制來建模,以上兩個就已經可以讓Scheme為所欲為了,記得以前網上有個QBasic的Scheme實作就是利用的這個,而我們當然也可以再來考慮更一般的Scheme程式設計,利用算子中的閉包傳遞,我們一樣可以設計出好的內部DSL,

  我們這里并不打算用Scheme或者別的Lisp來講解,這里依然用我們常用的宿主語言來,比如Python,Python其實是一種抽象度極高的語言,它比Scheme少的東西在我看來也就宏和continuation,再有就是尾遞回沒有優化,

 

  我們考慮以下這樣的一段程式,

repeat 3 (
  repeat 4 (
    display("=")
  )
  newline()
  display("test")
  newline()
)
display("The end")
newline()

 

  雖然,也許我在此并沒有說明這段程式的意思,身經百戰的你應該早已想出本程式的輸出可能是

====
test
====
test
====
test
The end

  

  這里repeat n (...)就代表著把括號里面的內容執行n遍,而display函式則是把后面的內容列印出來,newline函式就是換行,這是一個最簡單的DSL了,但是在這個原理的基礎上我們其實可以做比如畫畫之類的程式,因為一般意義上的教孩子編程所用的畫畫不會構造過于繁瑣的圖形,從一開始就可以思考出整體如何畫,于是利用回圈就可以了,而不需要用到判斷(然而復雜意義上的圖畫可能不是這樣,可能是不斷的根據當前所畫內容決定之后所添加內容,這可能就得需要判斷),

  Scratch中畫圖程式示例如下:

  

 

  結果就是畫個正六邊形如下: 

  

 

   和上述的DSL基本是一致的,

 

  但既然是想在Python上做內部DSL,我們就得想一種方法嵌入到Python中,最自然的就是將之前的程式改寫就是如下:

run(
        repeat(3,
                repeat(4,
                        display("=")
                ),
                newline(),
                display("test"),
                newline()
        ),
        display("The end"),
        newline()
)

   既然沒有Scheme的Macro和Continuation,Python以上的方式也就是函式呼叫方式,只是把格式排了一下,加上縮進,從而比較容易看出語意,

 

  接下去考慮的就是具體如何實作:

  我們先從display開始,第一個直覺是display和Python的print是一樣的,

  于是我們就這樣設計了:

def display(s):
    print(s)

  看起來我們平常的單個display都OK了,然而很快我們就意識到如同repeat(2, display("test"))這樣的程式無法正常作業,因為display列印之后并沒有產生別的影響,repeat自然無從知道display的動作,從而無法把它的動作復制,

  從而display需要一點影響才能正常作業,一個方法就是通過變數傳遞出來,這是一個有副作用的手段,很多時候應該盡量去避免,于是,我們只考慮從display回傳值來解決問題,也就是display函式需要回傳display和display的引數的資訊,newline也需要回傳包含newline的資訊,repeat也要回傳repeat以及它所有引數的資訊,

  最容易想到的當然是用字串來表示上述資訊,  

def display(a):
        return "display " + a

def newline():
        return "newline"

  然后我們再接著寫repeat,

from functools import reduce
def repeat(times, *args):
        s = "repeat " + str(times) + '\n(\n'
        for arg in args:
                s += reduce(lambda a,b:a+b,map(lambda x:' '+x+'\n',arg.split('\n')))
        s += ")"
        return s

我們運行一下

  print(repeat(2, display("test")))

  得到

repeat 2
(
display test
)

  突然意識到,這樣不對啊,如此繼續下去,run函式完全成了一個語言的解釋器,這和我們之前討論的完全一樣,那我們就不回傳字串,回傳tuple、list之類的資料結構呢?換湯不換藥,還是那么回事,沒有什么新意,

  

閉包構建

 

  回避不了回傳值要包含函式和函式引數的問題,只是,我們可以采用別的方式來做到,也就是閉包,

  所謂閉包,是一種算子,把函式的引數資訊封進另外一個函式,最侄訓傳這個函式,以下舉一個簡單的例子就應該很明白了,

def addn(n):
    def f(x):
        return x+n
    return f

  或者用lambda,上述寫成

    addn = lambda n:lambda x:x+n

  使用的時候,比如我想得到一個函式,回傳輸入數得到加1的結果,那么addn(1)就是我所需要的函式,

  addn就是一個閉包,

 

  按照這個思路,我們先想想run函式如何寫,run的引數是一系列按先后順序要發生動作的函式,那么run只是按順序執行這些函式,

def run(*args):
        for arg in args:
                arg()

 

  然后,我們試圖撰寫display和newline,代碼可以如下:

def display(s):
        def f():
                print(s, end="")
        return f

def newline():
        def f():
                print("")
        return f

   

  我們發現使用run、display、newline可以讓運行結果完全隨我們的想法,

  接下來就是repeat,

  比如repeat(3, display("a"), newline()), 實際上應該是回傳一個函式其執行結果是回圈三次執行display("a")和newline()回傳的函式,雖然開始有點拗口,但代碼并不太復雜:  

def repeat(times, *args):
        def f():
                for i in range(times):
                        for arg in args:
                                arg()
        return f

 

  于是,到此為止,最簡單的只包含repeat、display、newline的DSL就已經完成了,

  我們運行設計之初的代碼,的確得到了想要的結果,

 

升級思路

 

  上面的這個DSL實在太簡單了,它雖然有回圈,但是沒有引入變數,自然也就沒有引入運算,也不會有條件分支,

  那么一切都從變數支持開始,變數意味著面向程序的程式在運行的程序中,除了程式當前運行的位置之外,還有其他的狀態,我們之前repeat、display、newline回傳的函式都是沒有引數的,這樣除了創造有副作用的函式,否則無法攜帶其他狀態轉變的資訊,

  于是我們可以考慮用一個字典來代表程式中所有變數的狀態,然后讓所有的閉包最終都回傳帶一個以這樣的表示變數的字典為引數的函式,

  于是這種情況下,run函式應該這樣寫:

def run(*args):
        var_list={}
        for arg in args:
                var_list = arg(var_list)

  上面的run_list就是我們所需要的代表所有變數的字典,

  在此基礎上,我們可以構造用來設定變數的函式和獲得變數的函式:

def set_value(k, v):
        def f(var_list):
                var_list[k] = to_value(v, var_list)
                return var_list
        return f
def get_value(k):
        return lambda var_list : var_list[k]

  重寫display和newline,回傳函式的引數中當然應該添加var_list,雖然兩者不是與變數直接關聯,但也似乎只需要保證把var_list直接回傳,以確保run以及別的閉包呼叫的正確即可,

def display(s):
        def f(var_list):
                print(s, end="")
                return var_list
        return f

def newline():
        def f(var_list):
                print("")
                return var_list
        return f

   然而,我們實際上并未細想,display后面接的如果是常量的話,上述的實作并沒有錯誤,但如果不是常量呢?比如display(get_value("i")),get_value("i")是一個函式,上述的print顯然不能把希望列印的值列印,

  于是我們按理應該在此判斷一下display的引數s,如果是函式,應該先求值一下再列印,

def display(s):
        def f(var_list):
                if type(s)==type(lambda x:x):
                        print(s(var_list),end="")
                else:
                        print(s, end="")
                return var_list
        return f

  上述判斷s的型別是函式,也可以使用

  from types import FunctionType

  isinstance(a, FunctionType)

  上述我們可以測驗一段代碼

run(
        set_value("i", 1),
        repeat(3,
                display(get_value("i")),
                newline()
        )
)

  運行結果是

1

1

1

  與我們想象的一致,從而基本驗證其正確性,

 

  當然,這還只是拋磚引玉一下,并沒有涉及到計算、條件分支、條件回圈以及continue、break,乃至于goto,甚至于變數作用域、函式等,甚至于,在這個模式上我們甚至還可以加上除錯模式,加入單步、斷點等除錯手段,

  對于具體做法此處不再展開,讀者可以自行思考,

  開頭的程式

  

  引入的東西相對于文中多一些,我們現在終于也有了一點眉目,程式代碼詳細如下面檔案中所示,恕不細說,

                                                                                                           

 

少兒編程教育的思考

 

  一個致力于少兒編程教育的朋友跟我聊天,說到新接手的一個班,雖然之前都在另一少兒編程平臺下學習了近一年,但卻連最基本的編程邏輯都不懂,雖然少兒編程教的一般是面向程序的編程,可是班上沒有一個小朋友可以理解流程圖這個東西,質數判斷本應是個很簡單的問題(當然,我們先不深入的看待此問題),然而甚至于他在班上把詳細的程序描述清楚了,小朋友也會按照程序用紙筆來判斷,可是一上程式全班沒有一個人可以寫出來,這位朋友很生氣,覺得連流程圖都不納入教學體系是個很過分的事情,因為流程圖是面向程序編程的基本抽象,小朋友最終連這么簡單的程式都編不出來只能說明之前的教學簡直就是應付,甚至欺騙,

  而我倒是跟他大談或許教學目的該為如何教會小朋友一步步學會自己制作少兒編程工具,當然可能是針對對編程非常感興趣的孩子,現實是,這樣的孩子少,可以這樣教的老師也少,從而無法產生合理的商業利益,于是,如何教好更多的孩子才是他所認為的教育之重,

  我一向認為老師教學生,不是復制自己,而是教會學生思考的方法,孩子學會思考的方法遠比手把手的做個老師的克隆更強,獨立做出一個程式,即使再爛,其價值遠超過老師全力指導下寫的高深程式,

  于是,還是應該把目光放回到我們目前教學的工具上,如何讓孩子真正的理解程式,倒未必一直要從純數學出發,也不需要什么高深演算法,什么函式式編程,先掌握面向程序的精髓吧,讓孩子可以自由的產生想法,再由想法變成代碼,時機成熟了,再告訴孩子,某些東西可以有,比如演算法,比如各種編程范式,當年日本圍棋,超一流棋手的搖籃木谷道場,老師對于學生不按老師的想法行棋都是要懲罰的,然而六大超一流棋手風格各異,并沒有按照老師的手段來行棋,換句話說,教育中,傳承是根,但挖掘潛力才更為重要,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/137173.html

標籤:其他

上一篇:C語言雙指標之盛最多水的容器

下一篇:精靈鼠從入口到出口最少減少速度(2019年嗶哩嗶哩校招真題)題解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more