go要点2

interface

nterface就是一组抽象方法的集合,它必须由其他非interface类型实现,而不能自我实现, Go通过interface实现了duck-typing:即”当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。

type Stringer interface {
     String() string
}
package main
import (
    "fmt"
    "strconv"
)

type Human struct {
    name string
    age int
    phone string
}

// 通过这个方法 Human 实现了 fmt.Stringer
func (h Human) String() string {
    return "❰"+h.name+" - "+strconv.Itoa(h.age)+" years -  ✆ " +h.phone+"❱"
}

func main() {
    Bob := Human{"Bob", 39, "000-7777-XXX"}
    fmt.Println("This Human is : ", Bob)
}
  • Comma-ok断言
    Go语言里面有一个语法,可以直接判断是否是该类型的变量: value, ok = element.(T),这里value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型。如果element里面确实存储了T类型的数值,那么ok返回true,否则返回false。
  • switch测试
    element.(type)语法不能在switch外的任何逻辑里面使用,如果你要在switch外面判断一个类型就使用comma-ok
for index, element := range list{
            switch value := element.(type) {
                case int:
                    fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
                case string:
                    fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
                case Person:
                    fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
                default:
                    fmt.Println("list[%d] is of a different type", index)
            }
        }
  • 嵌入interface
type Interface interface {
    sort.Interface //嵌入字段sort.Interface
    Push(x interface{}) //a Push method to push elements into the heap
    Pop() interface{} //a Pop elements that pops elements from the heap
}
  • reflect 反射机制
    https://blog.golang.org/laws-of-reflection

关键字

break    default      func    interface    select
case     defer        go      map          struct
chan     else         goto    package      switch
const    fallthrough  if      range        type
continue for          import  return       var
  • func 用于定义函数和方法
  • return 用于从函数返回
  • defer 用于类似析构函数
  • go 用于并发
  • select 用于选择不同类型的通讯
  • interface 用于定义接口
  • struct 用于定义抽象数据类型
  • break、case、continue、for、fallthrough、else、if、switch、goto、default 流程控制
  • chan用于channel通讯
  • type用于声明自定义类型
  • map用于声明map类型数据
  • range用于读取slice、map、channel数据

GO要点1

gopath

  • src 存放源代码(比如:.go .c .h .s等)
  • pkg 编译后生成的文件(比如:.a)
  • bin 编译后生成的可执行文件

go类型

rune, int8, int16, int32, int64和byte, uint8, uint16, uint32, uint64。其中rune是int32的别称,byte是uint8的别称,浮点数的类型有float32和float64两种(没有float类型),默认是float64。
Go还支持复数,它的默认类型是complex128(64位实数+64位虚数)。如果需要小一些的,也有complex64(32位实数+32位虚数)。复数的形式为RE + IMi,其中RE是实数部分,IM是虚数部分,而最后的i是虚数单位。

var c complex64 = 5+5i
//output: (5+5i)
fmt.Printf("Value is: %v", c)

array、slice、map

  • array就是数组,数组也就不能改变长度
  • slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。

make、new

  • 内建函数make(T, args)与new(T)有着不同的功能,make只能创建slice、map和channel,并且返回一个有初始值(非零)的T类型,而不是*T。本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个slice,是一个包含指向数据(内部array)的指针、长度和容量的三项描述符;在这些项目被初始化之前,slice为nil。对于slice、map和channel来说,make初始化了内部的数据结构,填充适当的值。
  • new(T)分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型T的零值。

switch

Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch, 但是可以使用fallthrough强制执行后面的case代码。

integer := 6
switch integer {
case 4:
    fmt.Println("The integer was <= 4")
    fallthrough
case 5:
    fmt.Println("The integer was <= 5")
    fallthrough
case 6:
    fmt.Println("The integer was <= 6")
    fallthrough
case 7:
    fmt.Println("The integer was <= 7")
    fallthrough
case 8:
    fmt.Println("The integer was <= 8")
    fallthrough
default:
    fmt.Println("default case")
}

函数

  • Panic
  • Recover

import

  • 相对路径
    import “./model” //当前文件同一目录的model目录,但是不建议这种方式来import
  • 绝对路径
    import “shorturl/model” //加载gopath/src/shorturl/model模块
  • 点操作
 import(
     . "fmt"
 )
fmt.Println("hello world")可以省略的写成Println("hello world")
  • 别名操作
 import(
     f "fmt"
 )
  • _操作
import (
        "database/sql"
        _ "github.com/ziutek/mymysql/godrv"
    )

_操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。

struct匿名字段

type Human struct {
    name string
    age int
    weight int
}

type Student struct {
    Human  // 匿名字段,那么默认Student就包含了Human的所有字段
    speciality string
}

通过匿名访问和修改字段相当的有用,但是不仅仅是struct字段,所有的内置类型和自定义类型都是可以作为匿名字段的。如果字段名有冲突遵循最外层的优先访问原则,访问内层的可以通过匿名字段名来访问

面向对象-method

method语法定义

func (r ReceiverType) funcName(parameters) (results)

在使用method的时候重要注意几点:

  • 虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样
  • method里面可以访问接收者的字段
  • 调用method通过.访问,就像struct里面访问字段一样
  • receiver既可以是值传递,也可以是引用传递
  • 可以用在你自定义的类型、内置类型、struct等各种类型上面
  • 如果一个method的receiver是*T,你可以在一个T类型的实例变量V上面调用这个method,而不需要&V去调用这个method
  • 如果一个method的receiver是T,你可以在一个*T类型的变量P上面调用这个method,而不需要 *P去调用这个method
  • 如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method。
package main

import (
    "fmt"
    "math"
)

type Rectangle struct {
    width, height float64
}

type Circle struct {
    radius float64
}

func (r Rectangle) area() float64 {
    return r.width*r.height
}

func (c Circle) area() float64 {
    return c.radius * c.radius * math.Pi
}


func main() {
    r1 := Rectangle{12, 2}
    r2 := Rectangle{9, 4}
    c1 := Circle{10}
    c2 := Circle{25}

    fmt.Println("Area of r1 is: ", r1.area())
    fmt.Println("Area of r2 is: ", r2.area())
    fmt.Println("Area of c1 is: ", c1.area())
    fmt.Println("Area of c2 is: ", c2.area())
}

可见性

Go语言没有像其它语言一样有public、protected、private等访问控制修饰符,它是通过字母大小写来控制可见性的,如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头表示能被其它包访问或调用(相当于public),非大写开头就只能在包内使用(相当于private,变量或常量也可以下划线开头)

Python 装饰器和 functools 模块

什么是装饰器?

在 Python 语言里第一次看到装饰器不免让人想到设计模式中的装饰模式——动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
好吧,Python 中的装饰器显然和装饰模式毫无关系。那 Python 中的装饰器到底是什么呢?
简而言之,装饰器提供了一种方法,在函数和类定义语句的末尾插入自动运行代码。Python 中有两种装饰器:函数装饰器和类装饰器。

函数装饰器

简单的装饰器例子:

[code]
def decorator(F): # 装饰器函数定义
print "I’m decorator"
return F

@decorator
def foo():
print ‘Hello World!’
# 上面等价于 foo = decorator(foo)

foo()
"""
I’m decorator
Hello World!
"""

decorator(foo)() # 所以这里的输出与 foo() 相同
"""
I’m decorator
Hello World!
"""
[/code]



从上面运行后结果看出,装饰器就是一个能够返回可调用对象(函数)的可调用对象(函数)。
具有封闭作用域的装饰器

[code]
def decorator(func): # 装饰器函数
print ‘in decorator’
def wrapper(*args):
print ‘in decorator wrapper’
wrapper._calls += 1
print "calls = %d" % (wrapper._calls)
func(*args)
wrapper._calls = 0
return wrapper

@decorator
def foo(x, y):
print "x = %d, y = %d" % (x, y)

foo(1, 2) # 第一次调用
"""
in decorator
in decorator wrapper
calls = 1
x = 1, y = 2
"""

foo(2, 3) # 第二次调用
"""
in decorator wrapper
calls = 2
x = 2, y = 3
"""
[/code]

可以看出第一次调用 foo(1, 2) 时,相当于

[code]
foo = decorator(foo)
foo(1, 2)
[/code]

第二次调用 foo(2, 3) 时 foo 已经为 decorator(foo) 的返回值了
再看看一个装饰器类来实现的:

[code]
class decorator: # 一个装饰器类
def __init__(self, func):
print ‘in decorator __init__’
self.func = func
self.calls = 0
def __call__(self, *args):
print ‘in decorator __call__’
self.calls += 1
print "calls = %d" % (self.calls)
self.func(*args)

@decorator
def foo(x, y):
print "x = %d, y = %d" % (x, y)

foo(1, 2) # 第一次调用
"""
in decorator __init__
in decorator __call__
calls = 1
x = 1, y = 2
"""

foo(2, 3) # 第二次调用
"""
in decorator __call__
calls = 2
x = 2, y = 3
"""
[/code]

装饰器参数

[code]
def decorator_wrapper(a, b):
print ‘in decorator_wrapper’
print "a = %d, b = %d" % (a, b)
def decorator(func):
print ‘in decorator’
def wrapper(*args):
print ‘in wrapper’
func(*args)
return wrapper
return decorator

@decorator_wrapper(1, 2) # 这里先回执行 decorator_wrapper(1, 2), 返回 decorator 相当于 @decorator
def foo(word):
print word

foo(‘Hello World!’)
"""
in decorator_wrapper
a = 1, b = 2
in decorator
in wrapper
Hello World!
[/code]

functools 模块

functools 模块中有三个主要的函数 partial(), update_wrapper() 和 wraps(), 下面我们分别来看一下吧。
partial(func[,args][, *keywords])
看源码时发现这个函数不是用 python 写的,而是用 C 写的,但是帮助文档中给出了用 python 实现的代码,如下:

[code]
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
[/code]

OK,可能一下子没看明白,那么继续往下看,看一下是怎么用的。我们知道 python 中有个 int([x[,base]]) 函数,作用是把字符串转换为一个普通的整型。如果要把所有输入的二进制数转为整型,那么就要这样写 int(’11’, base=2)。这样写起来貌似不太方便,那么我们就能用 partial 来实现值传递一个参数就能转换二进制数转为整型的方法。

[code]
from functools import partial
int2 = partial(int, base=2)
print int2(’11’) # 3
print int2(‘101′) # 5
from functools import partial
int2 = partial(int, base=2)
print int2(’11’) # 3
print int2(‘101’) # 5
[/code]

update_wrapper(wrapper, wrapped[, assigned][, updated])
看这个函数的源代码发现,它就是把被封装的函数的 module, name, doc 和 dict 复制到封装的函数中去,源码如下,很简单的几句:

[code]
WRAPPER_ASSIGNMENTS = (‘__module__’, ‘__name__’, ‘__doc__’)
WRAPPER_UPDATES = (‘__dict__’,)
def update_wrapper(wrapper,wrapped, assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES):
for attr in assigned:
setattr(wrapper, attr, getattr(wrapped, attr))
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
return wrapper
[/code]

具体如何用我们可以往下看一下。

[code]
def wraps(wrapped,assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES):
return partial(update_wrapper, wrapped=wrapped,assigned=assigned, updated=updated)

[/code]

好,接下来看一下是如何使用的,这才恍然大悟,一直在很多开源项目的代码中看到如下使用。

[code]
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print ‘Calling decorated function’
return f(*args, **kwds)
return wrapper

@my_decorator
def example():
"""这里是文档注释"""
print ‘Called example function’

example()

# 下面是输出
"""
Calling decorated function
Called example function
"""
print example.__name__ # ‘example’
print example.__doc__ # ‘这里是文档注释’
[/code]
其它参考链接

  • http://www.wklken.me/posts/2013/08/18/python-extra-functools.html
  • http://coolshell.cn/articles/11265.html
  • Python自动下载百度音乐分类

    [python]
    #-*- coding: utf-8 -*-
    import urllib
    import re
    from Api_tieba import tieba
    class BaiduMusic:
    def __init__(self, key_words, rate=0, start_num=0, end_num=1000):
    if rate>0:
    self.tieba=tieba()
    self.tieba.login_init("xx", "xx")
    self.tieba.login()
    self.search_url="http://music.baidu.com/search/tag?key="+str(key_words)
    self.base_url="http://music.baidu.com"
    self.start_num=start_num
    self.end_num=end_num
    self.rate=rate
    self.run()
    def run(self):
    for i in range(self.start_num/20, self.end_num/20):
    url=self.search_url+"&start="+str(i*20)+"&size=20"
    html = urllib.urlopen(url).read()
    uri = re.findall(r’/song/d+’, html, re.M)
    lst = []
    for i in uri:
    link =self. base_url+i+"/download"
    lst.insert(0, link)
    lst.reverse()
    for k in lst:
    if self.rate>0:
    res = self.tieba.urlopen(k)
    else:
    res=urllib.urlopen(k).read()

    down= re.findall(r’http:.+\/music\/.+[0-9a-z]’ ,res, flags=0)
    print down
    down_url=down[self.rate].replace("\", "")

    s1 = re.search(‘title=".*’,res, re.M).group()
    s2 = re.search(‘>.*<.a’, s1, re.M).group()
    s3 = s2[1:-3]

    if self.rate==0:
    s3=unicode(s3,"utf-8","ignore").encode("gb2312","ignore")
    print s3
    urllib.urlretrieve(down_url, "music\"+s3+".mp3")
    [/python]