一,反射
1.Go反射
- interface
interface(接口)是golang最重要的特性之一,Interface類型可以定義一組方法,但是這些不需要實現。並且interface不能包含任何變量。
- interface是方法的集合
- interface是一種類型,並且是指針類型
- interface的更重要的作用在於多態實現
- 接口的使用不僅僅針對結構體,自定義類型、變量等等都可以實現接口。
- 如果一個接口沒有任何方法,我們稱爲空接口,由於空接口沒有方法,所以任何類型都實現了空接口。
- 要實現一個接口,必須實現該接口裏面的所有方法。
- 反射就是用來檢測存儲在接口變量內部(值value;類型concrete type) pair對的一種機制。反射一般配合接口一起使用,反射使go語言更靈活。但是反射的效率比較慢。
用例: 反射其中一個用法是在數據庫映射時使用,將數據映射到結構體中。
/*
通過tag將map中的數據映射到結構體中
*/
func DataToStructByTag(data map[string]interface{}, obj interface{}, tagName string) (err error) {
valueObj := reflect.ValueOf(obj).Elem()
for i := 0; i < valueObj.NumField(); i++ {
value := data[valueObj.Type().Field(i).Tag.Get(tagName)]
valueR := reflect.ValueOf(value)
if valueR.Type().Name() != valueObj.Type().Field(i).Type.Name() {
err = fmt.Errorf("type %s cant convert to type %s.", valueR.Type().Name(), valueObj.Type().Field(i).Type.Name())
return
}
if valueObj.FieldByName(valueObj.Type().Field(i).Name).CanSet() {
valueObj.FieldByName(valueObj.Type().Field(i).Name).Set(valueR)
}
}
return
}
2.Python 反射
- hasattr,getattr,setattr,delattr
python裏面的反射是通過以上4種函數實現。hasattr用來判斷某個對象是否包含某個屬性或方法。getattr用來獲得某個屬性或方法。setattr是設置對象的屬性或方法。delattr刪除對象的屬性。
# 通過實例類對象來操作sql語句!!就是所謂的ORM
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 判斷是否需要保存
for k, v in attrs.items():
# 判斷是否是指定的StringField或者IntegerField的實例對象
if isinstance(v, tuple):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
# 刪除這些已經在字典中存儲的屬性
for k in mappings.keys():
attrs.pop(k)
# 將之前的uid/name/email/password以及對應的對象引用,類名字
attrs['__mappings__'] = mappings # 保存屬性和列的映射關係
attrs['__table__'] = name # 假設表名和類名一致
return type.__new__(cls, name, bases, attrs)
class User(metaclass=ModelMetaclass):
uid = ("uid", "int unsigned")
name = ("username", "varchar(30)")
price = ("price", "double")
email = ("email", "varchar(30)")
password = ("password", "varchar(30)")
# 當指定元類之後,以上的類屬性將不在類中,而是在__mappings__屬性指定的字典中存儲
# 以上User類中有
# __mappings__ = {
# "uid" : ("uid", "int unsigned"),
# "name" : ("username", "varchar(30)"),
# "email" : ("email", "varchar(30)"),
# "password" : ("password", "varchar(30)"),
# }
# __table__ = "User"
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
# self.name = value
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self, k, None))
# sql = 'inset into %s (%s) values (%s)' % (self.__table__,','.join(fields), ','.join([str(i) for i in args]))
args_temp = list()
for temp in args:
# 判斷如果是數字類型
if isinstance(temp, (int, float)):
args_temp.append(str(temp))
elif isinstance(temp, str):
args_temp.append("""'%s'""" % temp)
sql = 'insert into %s (%s) value (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
print("SQL: %s" % sql)
u = User(uid=12345, name='Michael', email='[email protected]', password='my_pwd', price=1.2)
print(u.__dict__)
u.save()
二,垃圾回收
1. Go的垃圾回收官方形容爲 非分代 非緊縮 寫屏障 三色併發標記清理算法。
非分代
不像Java那樣分爲年輕代和年老代,自然也沒有minor gc和maj o gc的區別。
非緊縮
在垃圾回收之後不會進行內存整理以清除內存碎片。
寫屏障
在併發標記的過程中,如果應用程序(mutator)修改了對象圖,就可能出現標記遺漏的可能,寫屏障就是爲了處理標記遺漏的問題。
三色
將GC中的對象按照搜索的情況分成三種:
- 黑色: 對象在這次GC中已標記,且這個對象包含的子對象也已標記
- 灰色: 對象在這次GC中已標記, 但這個對象包含的子對象未標記
- 白色: 對象在這次GC中未標記
併發
可以和應用程序(mutator)在一定程度上併發執行。
標記清理
GC算法分爲兩個大步驟:標記階段找出要回收的對象,清理階段則回收未被標記的對象(要被回收的對象)。
Go 歷史版本垃圾回收暫停時間
2. python垃圾回收
引用計數
Python垃圾回收主要以引用計數爲主,分代回收爲輔。引用計數法的原理是每個對象維護一個ob_ref,用來記錄當前對象被引用的次數,也就是來追蹤到底有多少引用指向了這個對象,當發生以下四種情況的時候,該對象的引用計數+1,當引用計數爲0時會被python虛擬機回收。
優點
- 高效
- 運行期沒有停頓 可以類比一下Ruby的垃圾回收機制,也就是 實時性:一旦沒有引用,內存就直接釋放了。不用像其他機制等到特定時機。實時性還帶來一個好處:處理回收內存的時間分攤到了平時。
- 對象有確定的生命週期
- 易於實現
缺點
- 維護引用計數消耗資源,維護引用計數的次數和引用賦值成正比,而不像mark and sweep等基本與回收的內存數量有關。
- 無法解決循環引用的問題。A和B相互引用而再沒有外部引用A與B中的任何一個,它們的引用計數都爲1,但顯然應該被回收。
手動回收
import gc
gc.collect()
三,標籤
- 跳出外層循環使用break label :
fmt.Println("in")
Loop:
for{
fmt.Println("outer")
for{
fmt.Println("inner")
break Loop
}
}
fmt.Println("out")
- python裏面沒有標籤,當要實現跳出多重循環時可以藉助異常:
class LoopBreakException(Exception):
pass
def loop_test():
try:
for i in range(1, 20):
for j in range(0,100):
if j % i == 13:
print(i, j)
raise LoopBreakException()
except LoopBreakException:
pass
if __name__ == '__main__':
loop_test()
- goto 語句可以讓程序切換到某個被 Label 標記的地方繼續執行。
i := 0
Start:
if i<10{
i+=1
goto Start
}else{
goto End
}
End:
四,多態
多態的字面意思是多種狀態,在面向對象的語言中,接口的多種不同的實現方式即爲多態。多態性是允許你將父對象設置成爲一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
“duck typing” 就是一個長得像鴨子,而且也有鴨子的特點的,我們就可以稱他爲鴨子;比如一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱爲鴨子。
type Greeting interface {
SayHello()
GetName()string
}
type Student struct{
Name string
}
func (s Student) SayHello() {
fmt.Printf("hello %s, stu\n",s.Name)
}
func (s Student) GetName() string {
return s.Name
}
func (t Teacher) SayHello() {
fmt.Printf("hello %s, teacher\n", t.Name)
}
func (t Teacher) GetName() string {
return t.Name
}
type Teacher struct{
Name string
}
func main(){
var greet Greeting
s := Student{Name:"Cui"}
t := Teacher{Name:"Duan"}
greet = s
name := greet.GetName()
fmt.Println(name)
greet.SayHello()
greet = t
name = greet.GetName()
fmt.Println(name)
greet.SayHello()
}
python的多態會使用一個函數來輔助實現,通過傳遞不同的實現了某個函數的class對象來達到不同的效果。
class Greeting(object):
def __init__(self, name):
self.name = name
def say_hello(self):
raise NotImplementedError
def get_name(self):
raise NotImplementedError
class Student(Greeting):
def __init__(self, name):
super(Student,self).__init__(name)
def say_hello(self):
print(f"hello {self.name}, stu")
def get_name(self):
return self.name
class Teacher(Greeting):
def __init__(self,name):
super(Teacher,self).__init__(name)
def say_hello(self):
print(f"hello {self.name}, teacher")
def get_name(self):
return self.name
def hello(obj):
if hasattr(obj, "say_hello"):
obj.say_hello()
else:
print("have not say_hello func.")
if __name__ == '__main__':
s = Student("Cui")
t = Teacher("Duan")
hello(s)
hello(t)