- 美國稱為投資銀行、歐洲稱為商人銀行、亞洲多稱為證券公司
- 狹義定義
- 初級市場:IBD部門-investment banking division
- 承銷業務:IPO、新股上市、發行債券等
- 次狹義定義-財務顧問:併購(M&A)、公司重組、股權轉讓
- 二級市場:GM部門-global markets
- S&T:sales是經紀(broker)為中間的牽線人替客戶買賣從中賺取傭金,trader是dealer自己作為客戶的交易對手從中賺價差
- FICC-Fixed Income, Currencies and Commodities
- S&T:sales是經紀(broker)為中間的牽線人替客戶買賣從中賺取傭金,trader是dealer自己作為客戶的交易對手從中賺價差
- 初級市場:IBD部門-investment banking division
- 廣義定義:
- 財富管理、私人銀行:面向個人
- 資產管理:面向機構、法人
- 基金、投信…台灣的用語?
- 私募股權-PE Private Equity
- 創投-VC Venture Capital
- 避險基金-HF Hedge Fund
- 共同基金 Mutual Fund
Effective Python – 例26 定義function decorators使用functools.wraps
python有簡單的語法來使用function decorators,但有可能造成一些不想要的副作用,例如可能會把help給覆蓋。
def trace(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
return result
return wrapper
@trace
def fibonacci(n):
"""Return the n-th Fibonacci number"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n -1))
# @trace 等於是 fibonacci = trace(fibonacci)
fibonacci(4)
help(fibonacci)
import pickle
pickle.dumps(fibonacci)
fibonacci((0,), {}) -> 0 fibonacci((1,), {}) -> 1 fibonacci((2,), {}) -> 1 fibonacci((1,), {}) -> 1 fibonacci((0,), {}) -> 0 fibonacci((1,), {}) -> 1 fibonacci((2,), {}) -> 1 fibonacci((3,), {}) -> 2 fibonacci((4,), {}) -> 3 Help on function wrapper in module __main__: wrapper(*args, **kwargs) Traceback (most recent call last): File "C:/Users/hans/Desktop/item 26.py", line 22, inpickle.dumps(fibonacci) AttributeError: Can't pickle local object 'trace. .wrapper'
在wrapper function加上wraps可以修好help跟pickle
from functools import wraps
def trace(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
return result
return wrapper
help(fibonacci)
print(pickle.dumps(fibonacci))
Help on function fibonacci in module __main__: fibonacci(n) Return the n-th Fibonacci number b'\x80\x04\x95\x1a\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\tfibonacci\x94\x93\x94.'
Effective python – 例33 在巢狀generators 使用yield from
def move(period, speed):
for _ in range(period):
yield speed
def pause(delay):
for _ in range(delay):
yield 0
def animate():
for delta in move(4, 5.0):
yield delta
for delta in pause(3):
yield delta
for delta in move(2, 3.0):
yield delta
def render(delta):
print(f'Delta: {delta:.1f}')
# Move the imgaes onscreen
...
def run(func):
for delta in func():
render(delta)
run(animate)
想像我們在螢幕上用不同速度輪播不同照片來做成動畫,有的時候也會在中間暫停一下。
Delta: 5.0
Delta: 5.0
Delta: 5.0
Delta: 5.0
Delta: 0.0
Delta: 0.0
Delta: 0.0
Delta: 3.0
Delta: 3.0
改用yield from不僅是看起來更簡潔,重點是可以獲得更佳的運算效能。
def animate_composed():
yield from move(4, 5.0)
yield from pause(3)
yield from move(2, 3.0)
run(animate_composed)
Effective Python – 例75 – 在debug時輸出repr字串
使用print()時通常是輸出所謂human readable字串,但有時會反而會造成困擾
print(5)
#5
print('5')
#5
int_value = 5
str_value = '5'
print(f'{int_value} == {str_value} ?')
#5 == 5 ?
我們可能分不清這個變數是字串’5’還是數值「5」。
另外有些字元可能不是printable,故print會看不到東西。
這時候可以改用rerp(),會改成所謂的printable representation的輸出。
a = '\x07'
print(a)
#
print(repr(a))
#'\x07'
Python有一個eval()可以把representation轉回成變數,但要知道eval()很容易造成問題,不該輕易使用。
b = eval(repr(a))
assert a == b
print(repr(5))
#5
print(repr('5'))
#'5'
print(f'{int_value}r != {str_value}r')
#5r != 5r
一些自訂的object預設的print()輸出可能會不如預期
class OpaqueClass:
def __init__(self, x, y):
self.x = x
self.y = y
obj = OpaqueClass(1, 'foo')
print(obj)
<main.OpaqueClass object at 0x037C9088>
我們可以用__repr__來設計repr()的預設行為,另外format string也可以用{}r來輸出
printable representation
class BetterClass:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'BetterClass({self.x!r}, {self.y!r})'
obj = BetterClass(2, 'bar')
print(obj)
BetterClass(2, ‘bar’)
class BetterClass2:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'BetterClass2({self.x!r}, {self.y!r})'
def __str__(self):
return f'in __str__ {self.x}, {self.y}'
obj = BetterClass2(3, 'bar')
print(obj)
print(repr(obj)
in __str__ 3, bar
BetterClass2(3, ‘bar’)
另外__str__可以設計print()的行為。
若__str__沒有修改,但有__repr__修改,print()會呼叫它。
obj = OpaqueClass(4, 'baz')
print(obj.__dict__)
{‘x’: 4, ‘y’: ‘baz’}
若不能修改物件,我們可以改用__dict__來得到物件的成員所組成的dict
Effective python – 例29 在comprehensions中使用assignment expressions
stock = {
'nails': 125,
'screws': 35,
'wingnuts': 8,
'washers': 24,
}
def get_batches(count, size):
return count // size
comprehensions是python常用的一個功能,可以快速生成list, dict, set等變數。但有時會出現一些重覆的計算…
order = ['screws', 'wingnuts', ' clips']
found = {name: get_batches(stock.get(name, 0), 8)
for name in order
if get_batches(stock.get(name, 0), 8)}
print(found)
{‘screws’: 4, ‘wingnuts’: 1}
現在我們可以用assignment expressions( :=,又稱walrus operator)來減少這些重覆語句的出現。
found = {name: batches for name in order
if (batches := get_batches(stock.get(name, 0), 8))}
print(found)
不過要小心assignment expressions可能會汙染comprehensions外的scope,所以本書只建議在if的區域使用assignment expressions。
half = [(last := count // 2) for count in stock.values()]
print(last)
#12
print(batches)
#0
但實際上if區域的變數也是會汙染,書中的建議原因不太確定為何。
Effective Python – 例14 在排序時使用key參數
例如list之類有序的容器可以用sort這個方法來做排序,但若是其中的物件沒辨法比較時(沒有實作< operator)會產生Error,這時用用key傳入一個function回傳可比較的物件來代替。
class Tool:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __repr__(self):
return f'Tool({self.name!r}, {self.weight})'
tools = [
Tool('level', 3.5),
Tool('hammer', 1.25),
Tool('screwdriver', 0.5),
]
tools.sort()
TypeError: ‘<‘ not supported between instances of ‘Tool’ and ‘Tool’
我們可以用一個lamda function來讓Tool物件以name元素來做排序。
tools.sort(key=lamda x: x.name)
print(tools)
[Tool(‘hammer’, 1.25), Tool(‘level’, 3.5), Tool(‘screwdriver’, 0.5)]
或是回傳一個tuple,sort會依照順序來做比較。
tools = [
Tool('sander', 4),
Tool('drill', 4),
Tool('circular saw', 0.5),
]
tools.sort(key=lambda x: (x.weight, x.name))
print(tools)
Tool(‘circular saw’, 0.5), Tool(‘drill’, 4), Tool(‘sander’, 4)]
另外可以用reverse參數或是負號來做反向排序
tools.sort(key=lambda x: (x.weight, x.name), reverse=True)
print(tools)
[Tool(‘sander’, 4), Tool(‘drill’, 4), Tool(‘circular saw’, 0.5)]
tools.sort(key=lambda x: (-x.weight, x.name), reverse=True)
print(tools)
[Tool(‘circular saw’, 0.5), Tool(‘sander’, 4), Tool(‘drill’, 4)]
Effective PYTHON – 例16: 檢查dictionary key值存在時,使用get而非KeyError
Effective PYTHON 2rd
在使用dictionary時,若key值不存在時會產生KeyError,我們有四種方式可以處理。
counters = {
'key1': 1,
'key2': 2
}
key = 'key0'
#法一:
#先檢查key值是否存在
if key in counters:
count = counters[key]
else:
count = 0
counters[key] = count + 1
#法二:
#用try/except處理KeyError
try:
count = counters[key]
except KeyError:
count = 0
counters[key] = count+1
#法三:
#使用get
count = counters.get(key, 0)
counters[key] = count + 1
#法四:
#使用setdefault
counters.setdefault(key, 0)
counters[key] += 1
get會把第一個引數當作key回傳對應的value,若key不存在不會丟出KeyError而是會回傳第一個引數的值,在此例中就會回傳0。若是沒有第二個引數會回傳None,在此例中應該比較推薦用get的用法。
而setdefault則會把value直接用第二個引數修改。通常是適合用在value是container的狀況,但書中建議這種情況可能要考慮用defaultdic來代替一般的dictionary。
key = 'key0'
votes = {
'key1': ['Bob', 'Alice'],
'key2': ['Coco']
}
names = votes.get(key)
if names is None:
votes[key] = names = []
#或是用 := (Walrus Operator, assignment expression)
if (names := votes.get(key)) is None:
votes[key] = names = []
#這種情況用setdefault最簡潔
names = votes.setdefault(key, [])
FIRE-工作10年就退休且財富自由
FIRE是Financial Independence Retire Early的縮寫,是在美國流行的一種理財概念。目標在工作10年存到足夠的退休金,並用這些資產進行被動投資,只要平均年報酬能等於一年的花費就可以達到提早退休的目標。
這篇主要的參考資料包括兩本書的中文譯本:
- 財務自由,提早過你真正想過的生活(FINANCIAL FREEDOM: A Proven Path to All the Money You Will Ever Need)
- 賺錢,更賺自由的FIRE理財族:低薪、負債、零存款、打工族……也能達到財務自由,享受人生 (Playing with FIRE (Financial Independence Retire Early): How Far Would You Go for Financial Freedom?)
財務自由與足夠的退休金這兩點可能很抽象。FIRE認為在美國大概一個家庭需要100萬美元的資產,這些資產可帶來每年40000美元的收入。當然每個人想過/能過的生活不一樣,書中所舉的範例每年32000-60000美元。
100萬美元約是3000萬新台幣,而40000美元的年消費約是120萬新台幣。但在台灣實行FIRE,需要計算台灣與美國的物價,我參考Numbo [1,2],約以70%物價來計算。也就是說在台灣約要2000萬新台幣才能退休,大概全家每年可以消費80萬新台幣。若換算32000~60000美元的年支出,在台灣是70萬至130萬新台幣。
在台灣實行FIRE的家庭,目標月支出是5.5萬至10萬
退休所需資產是1700萬~3100萬
對於被動收入的理解各流派差異相當大,但對被動投資者來說就是「4%法則」,也就認為每100萬的資產扣除通膨後平均可帶來4萬元的年收入。這是一個不卑不亢的數字,雖然景氣有好有壞,各公司的經營也不同。但被動投資將投資拉長至30年以上,並分散投資上百上千家公司,在分散風險後可帶來相當穩定的投資報酬。
被動投資的原理不是三言兩語可以道盡,有問題的人應詳閱這兩本書。我另外推薦「漫步華爾街」。
使用4%法則計算會發現要在工作10年後退休需要將⅔的收入存下來。也就一個人年收百萬,一年也只能花33萬,一個月能花的錢不超過二萬八,這是窮學生過的生活。但你一年可以存下66萬元,十年後就可以存下666萬,加上每年4%投資報酬會變成830萬,830萬的4%就是33萬。接下來你就可以拿每年33萬的收入過財富自由的生活。
在台灣要實行FIRE最低需要家庭年收200萬,且將每月消費壓低至5.5萬
FIRE提早退休的核心就是減少不必要的花費,並不是教你什麼神奇的投資法。
當然有100萬的年收我不會選擇過每月二萬八的窮學生生活。FIRE告訴我早早退休並不是辦不到的事情,只是我選擇了更好的物質生活,所以才要這麼努力工作。
附註
[1] 全球物價指數排名出爐!台灣物價其實很低?-依這篇文章記錄,台北的物價約是紐約的75%
[2] Numbeo – 在這寫這篇文章時所計算的台北物價是紐約的65%
既然是退休時的花費,就不應該用各國最大城市來計算物價,但台灣小城市的物價資料不足,如果大家覺得70%計算不合理,在60-80%左右的區間調整應該還算合理。
要不要買房在這兩本FIRE的書中沒有一致見解。其中一本建議盡早買房,因為提早投資不動產就是加大投資的時間以及報酬,但要買郊區便宜的二手房子。另一本書的範例中有人買房也有租房,甚至是住拖車的例子。一般來說租金或不動產應該是支出或是總資產的30%以下,再怎麼多也不應該超過40%。
雖然其中一本書說打工族也可以FIRE,但若在台灣月收3萬要實行FIRE,一個月只能花一萬。我認為還是有些困難,FIRE在台灣的最低標可能還是要月收5萬以上才辦得到。
這兩本書所採用的被動投資都是以美國股市為主,美國與非美國的比例約是8:2,考量到這些作者都是在美國退休這個數字是合理的。另外股債比約是8:2,因為這兩本書都建議在財富自由後還是要繼續工作,所以要選100%股市也是合理的。
財富自由不代表完全不工作,而是讓你可以不用在意薪水去選擇你喜歡的工作與生活
軟體工程師必讀的經典書籍
下面是我整理一些有名的軟體或CS相關書籍,不過多少會有其他的書籍被遺漏。
粗體是我個人推薦的書籍
ZONE 1
Refactoring |
Clean code |
Design Patterns: Elements of Reusable Object-Oriented Software |
Head first design pattern |
The Mythical Man-Month |
Domain-Driven Design: Tackling Complexity in the Heart of Software |
The Phoenix Project: A Novel about IT, DevOps, and Helping Your Business Win |
ZONE 2
The pragmatic programmer |
Programming pearls |
Code complete |
Don’t Make Me Think, Revisited: A Common Sense Approach to Web Usability |
Peopleware |
Designing Data-Intensive Applications |
Working Effectively with Legacy Code |
Building Microservices |
程式設計師的自我修養-連結、載入、程式庫 |
DevOps Handbook中文版|打造世界級技術組織的實踐指南
這本書不如“鳳凰計畫”有名,但我認為就算看過“鳳凰計畫”的人也還是很值得一讀。這本書會把“鳳凰計畫”裡面提到的「三步工作法」詳盡說明,但這本書所提的devops並沒有明確指出要用的流程或是工具,比較偏概念還有各公司採用的devops元素作簡介。
再對本書內容介紹前,我先以自己的解讀做總結。
- 自動化開發——bug, feature, 需求的自動化管理。並非只有coding的流程,所有高層主管以及客戶提出的需求都要有自動化的紀錄與追蹤。這樣才能統計所有的意見實行的狀況與成果。
- 自動化測試與部署——這是大部分人所以為的devops,但只有這個部分是沒有辦法達成devops的精神
- 自動化監控——除了監控以外,還要能提供客觀的方式來做評估產品。
- 部署後自動化測試——這也可算是監控的一部分,但自動化的測試可以提供更可靠且客觀的評估。更激烈的手段如“搗亂猴”,甚至主動內部攻擊來做測試。
- 將上述步驟以程式化自動執行,反覆循環執行並改進。
- 創造由上而下的devops文化,而非只是任命或雇用devops工程師。
目前大部份的devops可能都只關注在第二點,但實際上要從一到五點重覆循環改進才是真正的devops精神。
三步工作法其實是有很多抽象的概念與文化,自動化也只是手段之一。所以我認為最最重要的點還是第六點,要達成的最好方法就是推薦你的同事或主管來閱讀這本書。