本節內容:
- 面向對象高級語法部分
- 經典類vs新式類
- 靜態方法、類方法、屬性方法
- 類的特殊方法
- 反射
- 異常處理
- Socket開發基礎
面向對象高級語法部分
經典類vs新式類
把下面代碼用python2 和python3都執行一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#_*_coding:utf-8_*_
class
A:
def
__init__(
self
):
self
.n
=
'A'
class
B(A):
# def __init__(self):
# self.n = 'B'
pass
class
C(A):
def
__init__(
self
):
self
.n
=
'C'
class
D(B,C):
# def __init__(self):
# self.n = 'D'
pass
obj
=
D()
print
(obj.n)
|
classical vs new style:
- 經典類:深度優先
- 新式類:廣度優先
- super()用法
抽象接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import
abc
class
Alert(
object
):
'''報警基類'''
__metaclass__
=
abc.ABCMeta
@abc
.abstractmethod
def
send(
self
):
'''報警消息發送接口'''
pass
class
MailAlert(Alert):
pass
m
=
MailAlert()
m.send()
|
上面的代碼僅在py2裏有效,python3裏怎麼實現呢?
靜態方法
通過@staticmethod裝飾器即可把其裝飾的方法變爲一個靜態方法,什麼是靜態方法呢?其實不難理解,普通的方法,可以在實例化後直接調用,並且在方法裏可以通過self.調用實例變量或類變量,但靜態方法是不可以訪問實例變量或類變量的,一個不能訪問實例變量和類變量的方法,其實相當於跟類本身已經沒什麼關係了,它與類唯一的關聯就是需要通過類名來調用這個方法
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class
Dog(
object
):
def
__init__(
self
,name):
self
.name
=
name
@staticmethod
#把eat方法變爲靜態方法
def
eat(
self
):
print
(
"%s is eating"
%
self
.name)
d
=
Dog(
"tom"
)
d.eat()
|
上面的調用會出以下錯誤,說是eat需要一個self參數,但調用時卻沒有傳遞,沒錯,當eat變成靜態方法後,再通過實例調用時就不會自動把實例本身當作一個參數傳給self了。
1
2
3
4
5
|
Traceback (most recent call last):
File
"/Users/jieli/PycharmProjects/python基礎/自動化day7面向對象高級/靜態方法.py"
, line
17
,
in
<module>
d.eat()
TypeError: eat() missing
1
required positional argument:
'self'
<
/
module>
|
想讓上面的代碼可以正常工作有兩種辦法
1. 調用時主動傳遞實例本身給eat方法,即d.eat(d)
2. 在eat方法中去掉self參數,但這也意味着,在eat中不能通過self.調用實例中的其它變量了
1 class Dog(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @staticmethod 7 def eat(): 8 print(" is eating") 9 10 11 12 d = Dog("tom") 13 d.eat()
類方法
類方法通過@classmethod裝飾器實現,類方法和普通方法的區別是, 類方法只能訪問類變量,不能訪問實例變量
1
2
3
4
5
6
7
8
9
10
11
12
|
class
Dog(
object
):
def
__init__(
self
,name):
self
.name
=
name
@classmethod
def
eat(
self
):
print
(
"%s is eating"
%
self
.name)
d
=
Dog(
"tom"
)
d.eat()
|
執行報錯如下,說Dog沒有name屬性,因爲name是個實例變量,類方法是不能訪問實例變量的
1
2
3
4
5
6
|
Traceback (most recent call last):
File
"/Users/jieli/PycharmProjects/python基礎/自動化day7面向對象高級/類方法.py"
, line
16
,
in
<module>
d.eat()
File
"/Users/jieli/PycharmProjects/python基礎/自動化day7面向對象高級/類方法.py"
, line
11
,
in
eat
print
(
"%s is eating"
%
self
.name)
AttributeError:
type
object
'Dog'
has no attribute
'name'
|
此時可以定義一個類變量,也叫name,看下執行效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class
Dog(
object
):
name
=
"我是類變量"
def
__init__(
self
,name):
self
.name
=
name
@classmethod
def
eat(
self
):
print
(
"%s is eating"
%
self
.name)
d
=
Dog(
"tom"
)
d.eat()
#執行結果
我是類變量
is
eating
|
屬性方法
屬性方法的作用就是通過@property把一個方法變成一個靜態屬性
1
2
3
4
5
6
7
8
9
10
11
12
|
class
Dog(
object
):
def
__init__(
self
,name):
self
.name
=
name
@property
def
eat(
self
):
print
(
" %s is eating"
%
self
.name)
d
=
Dog(
"tom"
)
d.eat()
|
調用會出以下錯誤, 說NoneType is not callable, 因爲eat此時已經變成一個靜態屬性了, 不是方法了, 想調用已經不需要加()號了,直接d.eat就可以了
1
2
3
4
5
|
Traceback (most recent call last):
ChenRonghua
is
eating
File
"/Users/jieli/PycharmProjects/python基礎/自動化day7面向對象高級/屬性方法.py"
, line
16
,
in
<module>
d.eat()
TypeError:
'NoneType'
object
is
not
callable
|
正常調用如下
1
2
3
4
5
|
d
=
Dog(
"tom"
)
d.eat
輸出
ChenRonghua
is
eating
|
好吧,把一個方法變成靜態屬性有什麼卵用呢?既然想要靜態變量,那直接定義成一個靜態變量不就得了麼?well, 以後你會需到很多場景是不能簡單通過 定義 靜態屬性來實現的, 比如 ,你想知道一個航班當前的狀態,是到達了、延遲了、取消了、還是已經飛走了, 想知道這種狀態你必須經歷以下幾步:
1. 連接航空公司API查詢
2. 對查詢結果進行解析
3. 返回結果給你的用戶
因此這個status屬性的值是一系列動作後纔得到的結果,所以你每次調用時,其實它都要經過一系列的動作才返回你結果,但這些動作過程不需要用戶關心, 用戶只需要調用這個屬性就可以,明白 了麼?
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status " % self.flight_name) return 1 @property def flight_status(self): status = self.checking_status() if status == 0 : print("flight got canceled...") elif status == 1 : print("flight is arrived...") elif status == 2: print("flight has departured already...") else: print("cannot confirm the flight status...,please check later") f = Flight("CA980") f.flight_status
cool , 那現在我只能查詢航班狀態, 既然這個flight_status已經是個屬性了, 那我能否給它賦值呢?試試吧
1
2
3
|
f
=
Flight(
"CA980"
)
f.flight_status
f.flight_status
=
2
|
輸出, 說不能更改這個屬性,我擦。。。。,怎麼辦怎麼辦。。。
1
2
3
4
5
6
|
checking flight CA980 status
flight
is
arrived...
Traceback (most recent call last):
File
"/Users/jieli/PycharmProjects/python基礎/自動化day7面向對象高級/屬性方法.py"
, line
58
,
in
<module>
f.flight_status
=
2
AttributeError: can't
set
attribute
|
當然可以改, 不過需要通過@proerty.setter裝飾器再裝飾一下,此時 你需要寫一個新方法, 對這個flight_status進行更改。
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status " % self.flight_name) return 1 @property def flight_status(self): status = self.checking_status() if status == 0 : print("flight got canceled...") elif status == 1 : print("flight is arrived...") elif status == 2: print("flight has departured already...") else: print("cannot confirm the flight status...,please check later") @flight_status.setter #修改 def flight_status(self,status): status_dic = { 0 : "canceled", 1 :"arrived", 2 : "departured" } print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) ) @flight_status.deleter #刪除 def flight_status(self): print("status got removed...") f = Flight("CA980") f.flight_status f.flight_status = 2 #觸發@flight_status.setter del f.flight_status #觸發@flight_status.deleter
注意以上代碼裏還寫了一個@flight_status.deleter, 是允許可以將這個屬性刪除
類的特殊成員方法
1. __doc__ 表示類的描述信息
1
2
3
4
5
6
7
8
|
class
Foo:
""" 描述類信息,這是用於看片的神奇 """
def
func(
self
):
pass
print
Foo.__doc__
#輸出:類的描述信息
|
2. __module__ 和 __class__
__module__ 表示當前操作的對象在那個模塊
__class__ 表示當前操作的對象的類是什麼
![](http://static.javashuo.com/static/loading.gif)
class C: def __init__(self): self.name = 'tom'
![](http://static.javashuo.com/static/loading.gif)
from lib.aa import C obj = C() print obj.__module__ # 輸出 lib.aa,即:輸出模塊 print obj.__class__ # 輸出 lib.aa.C,即:輸出類
3. __init__ 構造方法,通過類創建對象時,自動觸發執行。
4.__del__
析構方法,當對象在內存中被釋放時,自動觸發執行。
注:此方法一般無須定義,因爲Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因爲此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的
5. __call__ 對象後面加括號,觸發執行。
注:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
1
2
3
4
5
6
7
8
9
10
11
12
|
class
Foo:
def
__init__(
self
):
pass
def
__call__(
self
,
*
args,
*
*
kwargs):
print
'__call__'
obj
=
Foo()
# 執行 __init__
obj()
# 執行 __call__
|
6. __dict__ 查看類或對象中的所有成員
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class
Province:
country
=
'China'
def
__init__(
self
, name, count):
self
.name
=
name
self
.count
=
count
def
func(
self
,
*
args,
*
*
kwargs):
print
'func'
# 獲取類的成員,即:靜態字段、方法、
print
Province.__dict__
# 輸出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
obj1
=
Province(
'HeBei'
,
10000
)
print
obj1.__dict__
# 獲取 對象obj1 的成員
# 輸出:{'count': 10000, 'name': 'HeBei'}
obj2
=
Province(
'HeNan'
,
3888
)
print
obj2.__dict__
# 獲取 對象obj1 的成員
# 輸出:{'count': 3888, 'name': 'HeNan'}
|
7.__str__ 如果一個類中定義了__str__方法,那麼在打印 對象 時,默認輸出該方法的返回值。
1
2
3
4
5
6
7
8
9
|
class
Foo:
def
__str__(
self
):
return
'alex li'
obj
=
Foo()
print
obj
# 輸出:alex li
|
8.__getitem__、__setitem__、__delitem__
用於索引操作,如字典。以上分別表示獲取、設置、刪除數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
Foo(
object
):
def
__getitem__(
self
, key):
print
(
'__getitem__'
,key)
def
__setitem__(
self
, key, value):
print
(
'__setitem__'
,key,value)
def
__delitem__(
self
, key):
print
(
'__delitem__'
,key)
obj
=
Foo()
result
=
obj[
'k1'
]
# 自動觸發執行 __getitem__
obj[
'k2'
]
=
'alex'
# 自動觸發執行 __setitem__
del
obj[
'k1'
]
|
9. __new__ \ __metaclass__
1
2
3
4
5
6
7
8
|
class
Foo(
object
):
def
__init__(
self
,name):
self
.name
=
name
f
=
Foo(
"tom"
)
|
上述代碼中,obj 是通過 Foo 類實例化的對象,其實,不僅 obj 是一個對象,Foo類本身也是一個對象,因爲在Python中一切事物都是對象。
如果按照一切事物都是對象的理論:obj對象是通過執行Foo類的構造方法創建,那麼Foo類對象應該也是通過執行某個類的 構造方法 創建。
1
2
|
print
type
(f)
# 輸出:<class '__main__.Foo'> 表示,obj 對象由Foo類創建
print
type
(Foo)
# 輸出:<type 'type'> 表示,Foo類對象由 type 類創建
|
所以,f對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建。
那麼,創建類就可以有兩種方式:
a). 普通方式
1
2
3
4
|
class
Foo(
object
):
def
func(
self
):
print
'hello alex'
|
b). 特殊方式
1
2
3
4
5
6
7
|
def
func(
self
):
print
'hello tom'
Foo
=
type
(
'Foo'
,(
object
,), {
'func'
: func})
#type第一個參數:類名
#type第二個參數:當前類的基類
#type第三個參數:類的成員
|
def func(self): print("hello %s"%self.name) def __init__(self,name,age): self.name = name self.age = age Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) f = Foo("jack",22) f.func()
So ,孩子記住,類 是由 type 類實例化產生
那麼問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?
答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以爲 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 4 print("Mytype __init__",*args,**kwargs) 5 6 def __call__(self, *args, **kwargs): 7 print("Mytype __call__", *args, **kwargs) 8 obj = self.__new__(self) 9 print("obj ",obj,*args, **kwargs) 10 print(self) 11 self.__init__(obj,*args, **kwargs) 12 return obj 13 14 def __new__(cls, *args, **kwargs): 15 print("Mytype __new__",*args,**kwargs) 16 return type.__new__(cls, *args, **kwargs) 17 18 print('here...') 19 class Foo(object,metaclass=MyType): 20 21 22 def __init__(self,name): 23 self.name = name 24 25 print("Foo __init__") 26 27 def __new__(cls, *args, **kwargs): 28 print("Foo __new__",cls, *args, **kwargs) 29 return object.__new__(cls) 30 31 f = Foo("tom") 32 print("f",f) 33 print("fname",f.name)
類的生成 調用 順序依次是 __new__ --> __init__ --> __call__
metaclass 詳解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那個答案寫的非常好
反射
python中的反射功能是由以下四個內置函數提供:hasattr、getattr、setattr、delattr,改四個函數分別用於對對象內部執行:檢查是否含有某成員、獲取成員、設置成員、刪除成員。
def getattr(object, name, default=None): # known special case of getattr """ getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. """ pass
![](http://static.javashuo.com/static/loading.gif)
判斷object中有沒有一個name字符串對應的方法或屬性
def setattr(x, y, v): # real signature unknown; restored from __doc__ """ Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v''
def delattr(x, y): # real signature unknown; restored from __doc__ """ Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y'' """
class Foo(object): def __init__(self): self.name = 'tom' def func(self): return 'func' obj = Foo() # #### 檢查是否含有成員 #### hasattr(obj, 'name') hasattr(obj, 'func') # #### 獲取成員 #### getattr(obj, 'name') getattr(obj, 'func') # #### 設置成員 #### setattr(obj, 'age', 18) setattr(obj, 'show', lambda num: num + 1) # #### 刪除成員 #### delattr(obj, 'name') delattr(obj, 'func')
動態導入模塊
1
2
3
4
|
import
importlib
__import__
(
'import_lib.metaclass'
)
#這是解釋器自己內部用的
#importlib.import_module('import_lib.metaclass') #與上面這句效果一樣,官方建議用這個
|
異常處理
1、異常基礎
在編程過程中爲了增加友好性,在程序出現bug時一般不會將錯誤信息顯示給用戶,而是現實一個提示的頁面,通俗來說就是不讓用戶看見大黃頁!!!
1
2
3
4
|
try
:
pass
except
Exception,ex:
pass
|
需求:將用戶輸入的兩個數字相加
while True: num1 = raw_input('num1:') num2 = raw_input('num2:') try: num1 = int(num1) num2 = int(num2) result = num1 + num2 except Exception, e: print '出現異常,信息如下:' print e
2、異常種類
python中的異常種類非常多,每個異常專門用於處理某一項異常!!!
AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x IOError 輸入/輸出異常;基本上是無法打開文件 ImportError 無法引入模塊或包;基本上是路徑問題或名稱錯誤 IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊 IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5] KeyError 試圖訪問字典裏不存在的鍵 KeyboardInterrupt Ctrl+C被按下 NameError 使用一個還未被賦予對象的變量 SyntaxError Python代碼非法,代碼不能編譯(個人認爲這是語法錯誤,寫錯了) TypeError 傳入對象類型與要求的不符合 UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量, 導致你以爲正在訪問它 ValueError 傳入一個調用者不期望的值,即使值的類型是正確的
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
dic = ["wupeiqi", 'alex'] try: dic[10] except IndexError, e: print e
![](http://static.javashuo.com/static/loading.gif)
dic = {'k1':'v1'} try: dic['k20'] except KeyError, e: print e
s1 = 'hello' try: int(s1) except ValueError, e: print e
對於上述實例,異常類只能用來處理指定的異常情況,如果非指定異常則無法處理。
1
2
3
4
5
6
7
|
# 未捕獲到異常,程序直接報錯
s1
=
'hello'
try
:
int
(s1)
except
IndexError,e:
print
e
|
所以,寫程序時需要考慮到try代碼塊中可能出現的任意異常,可以這樣寫:
1
2
3
4
5
6
7
8
9
|
s1
=
'hello'
try
:
int
(s1)
except
IndexError,e:
print
e
except
KeyError,e:
print
e
except
ValueError,e:
print
e
|
萬能異常 在python的異常中,有一個萬能異常:Exception,他可以捕獲任意異常,即:
1
2
3
4
5
|
s1
=
'hello'
try
:
int
(s1)
except
Exception,e:
print
e
|
接下來你可能要問了,既然有這個萬能異常,其他異常是不是就可以忽略了!
答:當然不是,對於特殊處理或提醒的異常需要先定義,最後定義Exception來確保程序正常運行。
1
2
3
4
5
6
7
8
9
|
s1
=
'hello'
try
:
int
(s1)
except
KeyError,e:
print
'鍵錯誤'
except
IndexError,e:
print
'索引錯誤'
except
Exception, e:
print
'錯誤'
|
3、異常其他結構
1
2
3
4
5
6
7
8
9
10
11
12
|
try
:
# 主代碼塊
pass
except
KeyError,e:
# 異常時,執行該塊
pass
else
:
# 主代碼塊執行完,執行該塊
pass
finally
:
# 無論異常與否,最終執行該塊
pass
|
4、主動觸發異常
1
2
3
4
|
try
:
raise
Exception(
'錯誤了。。。'
)
except
Exception,e:
print
e
|
5、自定義異常
1
2
3
4
5
6
7
8
9
10
11
12
|
class
WupeiqiException(Exception):
def
__init__(
self
, msg):
self
.message
=
msg
def
__str__(
self
):
return
self
.message
try
:
raise
WupeiqiException(
'我的異常'
)
except
WupeiqiException,e:
print
e
|
6、斷言
1
2
3
4
5
|
# assert 條件
assert
1
=
=
1
assert
1
=
=
2
|
Socket 編程
socket通常也稱作"套接字",用於描述IP地址和端口,是一個通信鏈的句柄,應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。
socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,對於文件用【打開】【讀寫】【關閉】模式來操作。socket就是該模式的一個實現,socket即是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉)
socket和file的區別:
- file模塊是針對某個指定文件進行【打開】【讀寫】【關閉】
- socket模塊是針對 服務器端 和 客戶端Socket 進行【打開】【讀寫】【關閉】
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print 'server waiting...' conn,addr = sk.accept() client_data = conn.recv(1024) print client_data conn.sendall('不要回答,不要回答,不要回答') conn.close()
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',9999) sk = socket.socket() sk.connect(ip_port) sk.sendall('請求佔領地球') server_reply = sk.recv(1024) print server_reply sk.close()
WEB服務應用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/usr/bin/env python
#coding:utf-8
import
socket
def
handle_request(client):
buf
=
client.recv(
1024
)
client.send(
"HTTP/1.1 200 OK\r\n\r\n"
)
client.send(
|