zoukankan      html  css  js  c++  java
  • Go for Pythonistas Go and the Zen of Python 禅

    Go for Pythonistas

    https://talks.golang.org/2013/go4python.slide#1

    Things I don't like about Python (it'll be short)

    Beautiful and simple

    Dynamic typing - nice because it's concise, like Python.

    a = "hello"
    b = 1
    # but also
    a = 2

    Static typing - can be verbose, like Java or C++.

    Foo foo = new Foo();

    Static typing with inferred types, like Go.

    a := "hello"
    b := 1
    // but no
    a = 2

    Statically-typed Python? Check mypy and Cython.

    Run time pyrotechnics

    name = 'pythonista'
    
    # This code only works half of the time.
    if random.random() > 0.5:
        print 'hey '+name+', you win!'
    else:
        print 'sorry '+nane+', you lose'
    

    I don't want start a flame war here but ...

    100% code coverage is a symptom

    • Code coverage should point you to untested cases.
    • Not a way to find typos!
    • 100% code coverage doesn't mean bug free.

    Other things I don't like

    • Deploying - managing dependencies.
    • Performance - "not too slow" is often not fast enough.
    • Magic! (e.g.: __magic__**kargs__getattr__)

    A list of magic methods in Python:

    And I *do* like concurrency!

    A lot has been said about Python's infamous Global Interpreter Lock.

    You should watch Mindblowing Python GIL, by David Beazley.

    Things I like about Python

    Things I like about Python

    • Hashes and arrays are part of the language.
    • The standard library.
    • Magic! A bit of code can do a lot.

    A bit of code

    fib.py

    Have you ever heard of Fibonacci?

    def fib(n):
        a, b = 0, 1
        for i in range(n):
            a, b = b, a + b
        return b
    
    def fib_rec(n):
        if n <= 1:
            return 1
        else:
            return fib_rec(n-1) + fib_rec(n-2)
    
    for x in range(10):
        print fib(x), fib_rec(x)

    fib.go

    Something familiar?

    func fib(n int) int {
        a, b := 0, 1
        for i := 0; i < n; i++ {
            a, b = b, a+b
        }
        return b
    }
    
    func fibRec(n int) int {
        if n <= 1 {
            return 1
        }
        return fibRec(n-1) + fibRec(n-2)
    }
    
    func main() {
        for i := 0; i < 10; i++ {
            fmt.Println(fib(i), fibRec(i))
        }
    }


    Fibonacci without generators? What?

    Python generators are awesome.

    def fib(n):
        a, b = 0, 1
        for i in range(n):
            a, b = b, a + b
            yield a
    

    Mechanically complex.

    f = fib(10)
    try:
        while True:
            print f.next()
    except StopIteration:
        print 'done'
    

    But very easy to use.

    for x in fib(10):
        print x
    print 'done'

    Python generators

    Note the generator executes concurrently. Hmm... I like concurrency.

    Go concurrency

    Based on goroutines and channels.

    • Goroutines: very light processing actors (the gophers).
    • Channels: typed, synchronized, thread-safe pipes (the arrows).

    "Generator" goroutines

     

    "Generator" goroutines

    Uses a channel send instead of yield.

    func fib(c chan int, n int) {
        a, b := 0, 1
        for i := 0; i < n; i++ {
            a, b = b, a+b
            c <- a
        }
        close(c)
    }
    
    func main() {
        c := make(chan int)
        go fib(c, 10)
    
        for x := range c {
            fmt.Println(x)
        }
    }

    "Generator" goroutines

    A more generator-like style:

    func fib(n int) chan int {
        c := make(chan int)
        go func() {
            a, b := 0, 1
            for i := 0; i < n; i++ {
                a, b = b, a+b
                c <- a
            }
            close(c)
        }()
        return c
    }
    
    func main() {
        for x := range fib(10) {
            fmt.Println(x)
        }
    }

     

    Exercise: generating prime numbers

    Write a function that returns a channel and sends the first n prime numbers on
    it.

    Given the function prime:

    // prime returns true if n is a prime number.
    func prime(n int) bool {
        for i := 2; i < n; i++ {
            if n%i == 0 {
                return false
            }
        }
        return true
    }
    

    Use the Go playground:

    Solution: generating prime numbers

    func primes(n int) chan int {
        c := make(chan int)
        go func() {
            for i := 1; n > 0; i++ {
                if prime(i) {
                    c <- i
                    n--
                }
            }
            close(c)
        }()
        return c
    }
    
    func main() {
        for p := range primes(10) {
            fmt.Println(p)
        }
    }

    Exercise: Fibonacci primes

    Write a filterPrimes function that takes a channel of ints as a
    parameter and returns another channel of ints.

    All the prime numbers that filterPrimes receives from the input channel are
    sent into the output channel.

    Complete this code snippet:

    Solution: Fibonacci primes

    func filterPrimes(cin chan int) chan int {
        cout := make(chan int)
        go func() {
            for v := range cin {
                if prime(v) {
                    cout <- v
                }
            }
            close(cout)
        }()
        return cout
    }
    
    func main() {
        for p := range filterPrimes(fib(20)) {
            fmt.Println(p)
        }
    }

    But there's much more

    Goroutines and channels aren't just for generators. They can be used to model
    all kinds of concurrent systems.

    To learn more:

    Object-oriented Go

    Object-oriented Go

    A type declaration.

    type Name struct {
        First  string
        Middle string
        Last   string
    }
    

    A method declaration.

    func (n Name) String() string {
        return fmt.Sprintf("%s %c. %s", n.First, n.Middle[0], strings.ToUpper(n.Last))
    }
    

    Constructing a Name and using it.

        n := Name{"William", "Mike", "Smith"}
        fmt.Printf("%s", n.String())

    Methods on anything

    There's more to types than structs.

    type SimpleName string
    

    You can define methods on any type.

    func (s SimpleName) String() string { return string(s) }
    

    Or almost any type.

    func (s string) NoWay()

    You can only define methods on types within the same package.

    Duck typing

    Duck typing

    If it walks like a duck ...

    What defines a duck?

    • Is there an explicit list of "duck" features?
    • What if the duck is not exactly a duck?

    s/duck/file-like object/g

    Go interfaces

    Simply a set of methods.

    From the fmt package:

    type Stringer interface {
        String() string
    }

    fmt.Println calls the String method if the parameter is a Stringer.

        n = Name{"William", "Mike", "Smith"}
        fmt.Println(n)

    A type with all the methods of the interface implements the interface.

    Implicit satisfaction == No "implements"

    Structural typing: it doesn't just sound like a duck, it is a duck.

    And that's checked at compile time.

    Decorators

    Decorators

    A convenient way to wrap a function.

    def auth_required(myfunc):
        def checkuser(self):
            user = parse_qs(urlparse(self.path).query).get('user')
            if user:
                self.user = user[0]
                myfunc(self)
            else:
                self.wfile.write('unknown user')
        return checkuser
    

    A function can be decorated using @.

    class myHandler(BaseHTTPRequestHandler):
        @auth_required
        def do_GET(self):
            self.wfile.write('Hello, %s!' % self.user)

    Decorators

    If we run it.

    try:
        server = HTTPServer(('', PORT_NUMBER), myHandler)
        server.serve_forever()
    
    except KeyboardInterrupt:
        server.socket.close()
    

    This is unauthorized:

    This is authorized:

    Decorators in Go?

    Not exactly, but close enough.

    Go doesn't provide decorators in the language, but its function literal syntax and simple scoping rules make it easy to do something similar.

    var hiHandler = authRequired(
        func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))
        },
    )
    

    A wrapper function.

    func authRequired(f http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            if r.FormValue("user") == "" {
                http.Error(w, "unknown user", http.StatusForbidden)
                return
            }
            f(w, r)
        }
    }

    Decorators in Go?

    func main() {
        http.HandleFunc("/hi", hiHandler)
        http.ListenAndServe(":8080", nil)
    }

    This is unauthorized:

    This is authorized:

    Exercise: errors in HTTP handlers

    In Go, functions can return errors to indicate that something bad happened.

    The net/http package from the standard library defines the type HandlerFunc.

    type HandlerFunc func(ResponseWriter, *Request)

    But it's often useful to unify the error handling into a single function to avoid
    repetition.

    type errorHandler func(http.ResponseWriter, *http.Request) error
    

    Write a decorator that given a errorHandler returns a http.HandlerFunc.
    If an error occurs it logs it and returns an http error page.

    Exercise: errors in HTTP handlers (continuation)

    Given the function handler.

    func handler(w http.ResponseWriter, r *http.Request) error {
        name := r.FormValue("name")
        if name == "" {
            return fmt.Errorf("empty name")
        }
        fmt.Fprintln(w, "Hi,", name)
        return nil
    }
    

    We want to use it as follows.

        http.HandleFunc("/hi", handleError(handler))
    

    Implement handleError using the playground.

    Solution: errors in HTTP handlers

    func handleError(f errorHandler) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            err := f(w, r)
            if err != nil {
                log.Printf("%v", err)
                http.Error(w, "Oops!", http.StatusInternalServerError)
            }
        }
    }
    
        // Fake request without 'name' parameter.
        r := &http.Request{}
        w := newDummyResp()
        handleError(handler)(w, r)
        fmt.Println("resp a:", w)
    
        // Fake request with 'name' parameter 'john'.
        r.Form["name"] = []string{"john"}
        w = newDummyResp()
        handleError(handler)(w, r)
        fmt.Println("resp b:", w)

    Monkey patching

    Monkey patching

    "A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code." - Wikipedia

    Monkey patching

    Also known as "duck punching" ... poor duck.

    Often used for testing purposes.

    For example, say we want to test this function:

    def say_hi(usr):
        if auth(usr):
            print 'Hi, %s' % usr
        else:
            print 'unknown user %s' % usr
    

    Which depends on a function that makes an HTTP request:

    def auth(usr):
        try:
            r = urllib.urlopen(auth_url + '/' + usr)
            return r.getcode() == 200
        except:
            return False

    Monkey patching

    We can test say_hi without making HTTP requests by stubbing out auth:

    def sayhitest():
        # Test authenticated user
        globals()['auth'] = lambda x: True
        say_hi('John')
    
        # Test unauthenticated user
        globals()['auth'] = lambda x: False
        say_hi('John')

    Gopher punching!

    The same effect can be achieved in Go.

    func sayHi(user string) {
        if !auth(user) {
            fmt.Printf("unknown user %v
    ", user)
            return
        }
        fmt.Printf("Hi, %v
    ", user)
    }
    

    Which depends on

    var auth = func(user string) bool {
        res, err := http.Get(authURL + "/" + user)
        return err == nil && res.StatusCode == http.StatusOK
    }

    Gopher punching!

    Our test code can change the value of auth easily.

    func TestSayHi() {
        auth = func(string) bool { return true }
        sayHi("John")
    
        auth = func(string) bool { return false }
        sayHi("John")
    }

    Conclusion

    Go is a bit like Python

    • simple
    • flexible
    • fun

    but a bit different too

    • fast
    • concurrent
    • statically typed

    Disclaimer :

    • "No pythons, ducks, monkeys or gophers were harmed while writing this talk"

    Try it

    Next steps

    Learn Go from your browser

    The community: golang-nuts


    Go and the Zen of Python
    https://talks.golang.org/2012/zen.slide#1



  • 相关阅读:
    bzoj 1827: [Usaco2010 Mar]gather 奶牛大集会
    bzoj 1690: [Usaco2007 Dec]奶牛的旅行——分数规划+spfa判负环
    poj2728 最小比率生成树——01分数规划
    H265编码网页视频流媒体播放器EasyWasmPlayer.js播放控制台提示Uncaught TypeError排查
    EasyRTSPServer对接海康录像机无法正常预览如何解决?
    如何对EasyRTSPLive进行修改将其支持多通道拉RTSP流推RTMP流功能?
    H265视频流媒体播放器EasyPlayer.js播放HLS视频流无法自动播放原因排查分析
    从“地球漫游计划”看城市,TSINGSEE青犀视频让城市漫游直播更简单
    核污水排入大海?大到全球,小到城市,环境污染应该如何通过视频监控进行监管?
    AI如何让视频更智能?人工智能技术在视频监控中的应用
  • 原文地址:https://www.cnblogs.com/rsapaper/p/9764530.html
Copyright © 2011-2022 走看看