[Python] mixin與ABC(Abstract Base Classes)的比較

主要用途

  • mixin: code reuse,將一個或多個method的實作封裝,讓多個類別使用(這些類別不一定有繼承關係) (ref: Python cookbook 3rd, 8.17)
  • ABC: 定義介面(interface),或說是協定(protocal)及型別(type)的實作。(ref: Python cookbook 3rd, 8.13, Fluent Python ch10&11)

共同點

  • 都不能被實體化,故都不應該有__init()__

差異

  • 實作method
    • 因為要re use code故mixin一定會實作method;ABC大多不需要實作method,不過ABC可以實作method,但僅限用於ABC本身或是其supercall,也就是說ABC不應該為了instance實作method。
  • Instance variable
    • mixin不應該有instance variable,Effective Python建議讓mixin的__slots__ = (),阻止使用者建立新的attribute。

註:任何Class都只能繼承一個實體Class,其他只能繼承ABC或是mixin

Fluent Python有提到「An ABC may also be a mixin; The reverse is not true」,作者認為ABC可能為mix-in。但我認為這兩個概念不同,是否會有一個class同時符合這兩個概念的機會,我持懷疑態度。

另外Fluent Python ch12建議我們少用繼承,若是使用了很多繼承必須檢查我們是否有幾點問題

  • 是否正在重新發明輪子
  • 正在使用一個不好的Framwork
  • 是否有過度設計
  • 你是否正在設計一個新Framwork(除非你在設計新Framwork,否則不應使用太多的繼承)

[C11] 能否使用move()回傳一個新的物件但不copy物件

最近花了很多時間研究是否能以rvalue reference在不複製物件的狀態下回傳新物件
但仍然找不到方法

一般講到這個問題 大家一定是會回答RVO(return value optimization)
雖然目前的compiler大部份都會做到RVO 但我們還是不能說RVO一定會進行

我天真的以為rvalue reference跟move可以讓function回傳物件的scope在return之後續繼維持
但其實是我誤會這個功能
move constructor/assignment的設計上還是要先construct物件
不論如何 move constructor還是會消耗新的空間與時間用在construct
move assignment也一定要先construct物件才能再assign
我們能處理的是member variable要怎麼複製

#include <iostream>
#include <memory> //shared_ptr
using namespace std;
class Foo {
public:
    int* i;
    Foo() {
        i = new int[1];
        i[1] = 1;
        cout << "default constructor" << endl;
    }
    ~Foo() {
        if (i != nullptr) {
            cout << "destructor, i[0]=" << i[0] << endl;
            delete[] i;
        } else {
            cout << "destructor, i is nullptr" << endl;
        }
    }
    Foo(Foo&& f) {
        cout << "move constructor, f.i[0]=" << f.i[0] <<  endl;
        i = f.i;
	//假設i是一個很大的array我們可以省掉copy array的時間
	//但若i是一個物件 而且我們有很多個member variable如i, j ,k ,l ,m, n
	//move constructor還是要先construct每個member varialbe
        f.i = nullptr;
    }
    Foo& operator=(Foo&& f) {
        cout << "move assigment, f.i[0]=" << f.i[0] <<  endl;
        i = f.i;
        f.i = nullptr;
        return *this;
    }
};
Foo factory() {
    Foo f;
    f.i[0] = 9;
    //do something for Foo
    return std::move(f); //will call move contrcutor
}

Foo RVO_factory() {
    Foo f;
    f.i[0] = 8;
    return f;
}

Foo fail_RVO_factory(bool b) {
    if (b) {
        Foo f;
        f.i[0] = 2;
        return f;
    } else {
        Foo f;
        f.i[0] = 3;
        return f;
    }
}

shared_ptr<Foo> factory_shared_ptr() {
    shared_ptr<Foo> shared_f = make_shared<Foo>();
    shared_f->i[0] = 99;
    //do something for Foo
    return shared_f;
}
int main() {
    {
        Foo foo = move(Foo());//will call move constructor
        foo = move(Foo());//will call move assigment
    }
    cout << "===========================" << endl;
    {
        cout << "call factory" << endl;
        Foo f = factory();
        cout << "after factor, f.i[0]: " << f.i[0] << endl;
    }
    cout << "===========================" << endl;
    {
        cout << "call RVO factory" << endl;
        Foo f = RVO_factory();
        cout << "after RVO factor, f.i[0]: " << f.i[0] << endl;
    }
    cout << "===========================" << endl;
    {
        cout << "call fail RVO factory" << endl;
        Foo f = fail_RVO_factory(true);
        cout << "after fail RVO factor, f.i[0]: " << f.i[0] << endl;
    }
    cout << "===========================" << endl;
    {
        shared_ptr<Foo> shared_f = factory_shared_ptr();
        cout << "get shared_f.i[0]: " << shared_f->i[0] << endl;
    }
    cout << "exit shared_f scope" << endl;

    return 0;

在我的機器上的執行結果:

default constructor
move constructor, f.i[0]=1
destructor, i is nullptr
default constructor
move assigment, f.i[0]=1
destructor, i is nullptr
destructor, i[0]=1
===========================
call factory
default constructor
move constructor, f.i[0]=9
destructor, i is nullptr
after factor, f.i[0]: 9
destructor, i[0]=9
===========================
call RVO factory
default constructor
after RVO factor, f.i[0]: 8
destructor, i[0]=8
===========================
call fail RVO factory
default constructor
move constructor, f.i[0]=2
destructor, i is nullptr
after fail RVO factor, f.i[0]: 2
destructor, i[0]=2
===========================
default constructor
get shared_f.i[0]: 99
destructor, i[0]=99
exit shared_f scope

現在大部份的編譯器都應該有RVO
所以在call RVO factory時應該都只會construct一次

但RVO目前還是有限制
若是return的物件被包在if之類的條件中
編譯器沒辦法的編譯期確認回傳的物件是哪個
這樣就沒辦法做到RVO

總結來說
除非對自己處理記憶體空間很有自信
目前應該還是要優先考慮使用shared pointer
讓編譯器幫我們處理空間問題

而move就算了 若Foo不是我們寫的物件 我們能做的事情更少
假如寫Foo的人沒有寫move或是沒寫好 反而會造成更大的問題…

會計丙級 – 會計事務職類資丙級術科測試 重點整理

  • 費用認列
    • 雜誌書報應為「其他費用」
    • 電話費為「郵電費」
    • 題目沒列的項目不可以自行增加,需改用「其他費用」
  • 賒銷
    • 借貸方向與進貨和認列費用時相反,需注意不可弄反
    • 注意運費是由買家出還是賣家出,若由賣家出運費或是起運點交貨請認列費用
    • 運費若是現收請注意不可以把運費加到「應收帳款」裡,必須另列「現金」
  • 專利權攤銷應使用「各項攤堤」項目
  • 權責基礎=先實後虛;聯合基礎=先虛後實
  • 銷貨成本=期初存貨+進貨+進貨費用-進貨折讓-進貨退出-期末存貨
    • 借     |貸
    • 存貨(期末)|
    • 進貨折讓  |
    • 進貨退出  |
    • 銷貨成本  |
    •       |存貨(期初)
    •       |進貨
    •       |進貨運費
  • 進貨運費要算「進貨運費」而銷貨運費是算「運費」
  • 需留意的題目
    1. 103306:需調整期初試算表
    2. 103308:題目要求列印12/31「調整前」試算表,故必須在開帳後就列印,注意不可跟後面調整傳票弄混
    3. 103314:列印調整分錄之傳票
    4. 103315:需調整期初試算表
    5. 103318:期末調整需由調整後試算表逆推
    6. 103327、103328:需考慮營業稅

[Python] python的字串與轉碼問題:string and encode in 2.7/3.x

先以Python3為例子

>>> s = '你好'
>>> len(s)
2
>>> s[0]
'你'
>>> s[1]
'好'
>>> b = s.encode('utf8')
>>> b
b'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> len(b)
6
>>> b[0]
228
>>> b[1]
189
>>> type(b)
<class 'bytes'>
>>> type(s)
<class 'str'>

從上面可以看出來,在Python3裡面被單引號「’」或是雙引號「”」包起來的東西會被當成一個str。
在Python3裡面str是人類可讀的字串,所以中文的「你好」就會被拆成「你」「好」兩個字
實際上在記憶體中是沒辨法直接儲存中文,必須轉換成0與1的方式來儲存,但使用STR時沒必要去了解Python是怎麼儲存str。
我們還可以把str轉換成一連串數字,這件事情叫做「編碼(encode)」
可以想像成把人類可讀的文字轉成電腦可以儲存的電腦語言,Python3就叫做bytes。
一般來說目前最常用的編碼語言是「utf8」
「你好」轉成utf8就會變成6個byte 繼續閱讀 “[Python] python的字串與轉碼問題:string and encode in 2.7/3.x”

2018 投資去處

雖然身為一個被動投資人不應該認為市場是可以被預測的,但我還是認為PE可以某種程度預告未來的收益。

以目前(2018/2)的狀況來說全球股市的PE較歷史平均為高(ACWI:19.57)。雖然我目前還沒有明確的全球歷史平均值,但Shiller網頁告訴我們美國股市的歷史平均PE是15.69。已知長期平均的美國股市報酬略高於全球平均,故我推估全球歷史平均PE應該是17左右。

仔細研究會發現目前全球PE明顯被美國拉高,根據Shiller網頁告訴我們S&P500 PE與Shiller PE分別是24.46/31.69,而SPY(SPDR® S&P 500® ETF)告訴我們S&P500的PE是21.56。扣除美國之外的全球股市PE值還在合理的範圍內,以投美國除外的全球市場ETF—-IXUS(iShares Core MSCI Total International Stock ETF)來說目前是16.91,相較於我推估的歷史平均—-17,相差不多。

註:大部份etf網站所寫的pe值都是未來一年的預測,一般而言預測通常會有過度樂觀的現象故pe傾向被低估。故目前美國除外的全球市場PE應該還是略高於17。Shiller網頁所用的PE是十二個月的移動平均。

在Stock for the long run的24章中有這段話「4. Invest at least one-third of your equity portfolio in international stocks, currently defined as those not headquartered in the United States. Stocks in high-growth countries often become overpriced and yield poor returns for investors.」。作者建議讀者要投資三分一於非美國的股市,但不要過度投資成長型國家,因為成長型的股票代表著股價被高估的可能性很高,通常帶來的不是高成長而是低報酬。
後面作者更明確寫出不要「過度」投資PE高於20的國家:「Do not overweight high growth countries whose valuation ratio exceeds 20 times earnings. The data presented in Chapter 13 show that investors often overpay for such growth.」。雖然這段話最初是指當時熱門的新興國家,尤其是中國。諷刺地,目前反而是美股PE超過這個標準。我並不是預測美股接下來會崩盤,只是以用數據來提醒大家未來美股的報酬預期會較低。我不建議大家把持有的美國股市完全賣出或是放空美股,但根據PE來減少美股在資產配置中的比例我認為是一個合理的做法。

注:調整的資產配置要視為Funny money,一般而言Funny money不建議超過資產配置的10%。

漫步華爾街書中也提出高PE伴隨未來十年較低報酬的現象,但漫步華爾作者並沒有因此建議不要投資pe過高的國家或是在PE過高的時候減少股票配置。他提出另一個解釋,認為目前的高PE也伴隨著低通膨與低的債券利率,從股票風險溢酬與扣除通澎後的真實報酬率來看,目前的高PE也許是這樣造成的。
繼續閱讀 “2018 投資去處”

為何升息債券會下跌 又為何升息債券不一定下跌

Q:什麼是債券

A:

對於台灣人來說債券可能不太熟悉,但「定存」大家可能都知道是什麼,其實「定存」就有點像是一個「短期」的「銀行債券」。用不精確的白話來說,債券就是一些大型機構所發行可轉賣的「借據」。

你的好朋友「小明」可能最近打算想挖比特幣但缺錢買顯卡,所以跟你借了10萬塊,約定好一年後還你10萬元再加1萬的利息。同時「台積電」可能接到大筆「顯卡IC」定單,因產能不足想要借錢蓋更多工廠,台積電便打算公開發行「債券」。約定每張「債券」100萬元,你可以花100萬買這張「債券」,便可變成台積電的「債主」,台積電說好每年要給你一萬的利息共持續5年,5年後台積電會用100萬元把債券買回,買回後就算是還清債務並結束合約,台積電這次打算總共發行一萬張,故可借到100億來新建廠房。

定存一年就像是借錢給銀行一年,也就是一張一年的銀行債券,只是這張債券沒辦法轉賣只能解約。註:也是有定存可以轉讓,但台灣並不常見,你也可以想像當你要解約一筆100萬定存的時候,銀行只是把這筆定存轉賣給另一個同時間想要新開一筆100萬定存的人。

繼續閱讀 “為何升息債券會下跌 又為何升息債券不一定下跌”

[Python] 底線, name_mangling與private member

python並沒有所謂的private
但可以在member的前面加上一個底線 當作一個軟性的private
告訴其他人這個member不應讓其他人取用或修改 以達到安全性

我們也可以在member前面加上雙底線 這樣會產生name mangling的效果
但這樣也不能完全達到禁止存取

一般的情況下應該使用單底線來告知使用者即可(from fluent python ch9)
繼續閱讀 “[Python] 底線, name_mangling與private member”

[python] defaultdic, __call__

case1:
有時候我們會希望在dictionary中遞增value
但往往需要重複檢查key值是否存在並設定value為empty list, empty set或為0
這種情況使用setdefault或是sefaultdict就是一個好選擇

case2:
有時我們會希望function在執行時同時記錄一些狀態值
使用__call__來建立一個可以呼叫的物件 繼續閱讀 “ defaultdic, __call__”

醫師國考成績單補發及OSCE成績單補發

這篇ptt 醫學生版的文章可以參考:
https://www.ptt.cc/bbs/medstudent/M.1386212080.A.2B2.html

目前(2018/1)負責單位已經變成專技考試司第四科
聯絡電話要改為02-2236-9188 分機3708

建議直接寄e-mail過去申請即可
地址是moexpro4@mail.moex.gov.tw
然後需要填應考人應試成績補發申請表填好後e-mail申請即可
雖然對方說要3~5個工作天,但實際上我隔天就收到了

又OSCE成績單補發應直接找當初考試的醫院
除非是要申請osce證書才要找台灣醫學教育學會