python學(xué)習(xí)日記-2016.7.20

1.模塊

簡而言之,一個.py文件就是一個模塊。模塊的作用可總結(jié)為以下幾點(diǎn):
1.模塊可以提高代碼的可維護(hù)性
2.一次編寫就可以被其他地方引用
3.同名函數(shù)存在于不同模塊不會沖突
4.模塊名相同時可以使用不同的包名加以區(qū)別

模塊的特點(diǎn):
1.任何模塊的第一個字符串都被視為模塊的文檔注釋
2.__author__變量可以寫明作者

2.sys模塊中的argv

sys.argv[]是一個列表,里面存儲的是命令行的參數(shù),它至少擁有一個參數(shù),即argv[0],表示的是py文件的路徑,從第二個參數(shù)即argv[1]開始存儲你在命令行打的其他參數(shù)
舉例

import sys
def test():    
  args=sys.argv    
  if len(args)==1:        
    print('hello %s'%args[0])   
  elif len(args)==2:        
    print('hello,{0}{1}'.format(args[0],args[1]))    
  elif len(args)==3:        
    print('hello,{0},{1},{2}'.format(args[0],args[1],args[2]))
  if __name__=='__main__':    
    test()

然后在命令行用下面這個圖的方式運(yùn)行,就會有

運(yùn)行結(jié)果

由此我們可以看出ou就是argv[1],lalala就是argv[2],也就是命令行的第二和第三個參數(shù)

3.函數(shù)和變量的作用域

1.正常命名的函數(shù)和變量都是公開的(public),如a=1,def b()
2.以雙下劃線開頭和結(jié)尾的變量是特殊變量,可以直接被引用,如__author__,__name__
3.以單下劃線或雙下劃線開頭的函數(shù)和變量是私有的(private),模塊外不可見,只有模塊內(nèi)才能引用,如abc,abc,def abc()
4.外部不需要引用的函數(shù)全部定義成private,只有外部需要引用的函數(shù)才定義為public
5.如果要讓內(nèi)部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線

,在Python中,實(shí)例的變量名如果以
開頭,就變成了一個私有變量(private),只有內(nèi)部可以訪問,外部不能訪問,如

class Student(object): 
  def __init__(self, name, score): 
    self.__name = name 
    self.__score = score 
  def print_score(self): 
    print('%s: %s' % (self.__name, self.__score))

6.有些時候,你會看到以一個下劃線開頭的實(shí)例變量名,比如_name,這樣的實(shí)例變量外部是可以訪問的,但是,按照約定俗成的規(guī)定,當(dāng)你看到這樣的變量時,意思就是,“雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問”。

雙下劃線開頭的實(shí)例變量是不是一定不能從外部訪問呢?其實(shí)也不是。不能直接訪問__name是因?yàn)镻ython解釋器對外把__name變量改成了_Student__name,所以,仍然可以通過_Student__name來訪問__name變量:

print(bart._Student__name)
#'Bart Simpson'

7.對類的私有變量進(jìn)行訪問或修改使用get和set方法

4.安裝第三方模塊

python使用包管理工具pip來進(jìn)行第三方包的下載和管理
pip程序在你的python的安裝目錄下的Scripts文件夾中,如果你把pip的文件夾路徑加入到環(huán)境變量Path中,應(yīng)該就能直接在命令行中輸入pip --version可以查看到你的pip的版本信息,如果報錯了,那可能有幾方面的原因:
1.你安裝Python時沒有勾選安裝Pip,你可以看看你的Scripts文件夾下面有沒有pip.exe
2.你沒有把pip或python的目錄加入換件變量
3.你的電腦中安裝了多個pip程序,系統(tǒng)無法知道應(yīng)用哪一個
我在使用的時候就遇到了這個問題,這時候在命令行中輸入

where pip
截圖

出現(xiàn)了如上圖的情景,我以前安裝過的軟件中,其中自帶了strawberry,里面的perl中也有pip程序,這時候的解決辦法是直接cd到你的python的pip.exe的目錄下,再輸入pip install 包名,即可
如圖

運(yùn)行截圖

而后系統(tǒng)就會自動下載第三方包并保存,你可以在代碼中導(dǎo)入調(diào)用,如

#-*- coding=utf-8 -*-
'a test module'
from PIL import Image
im=Image.open('F:\a.jpg')
print(im.format,im.size,im.mode)
im.thumbnail((200,100))
im.save('F:\acopy.jpg','JPEG')

上述程序調(diào)用了Pillow中的Image為選定圖片生成一個縮略圖并保存在指定位置

5.類和實(shí)例

1.類是抽象的模板,比如Student類,而實(shí)例是根據(jù)類創(chuàng)建出來的一個個具體的“對象”,每個對象都擁有相同的方法,但各自的數(shù)據(jù)可能不同。
2.class后面緊接著是類名,即Student,類名通常是大寫開頭的單詞,緊接著是(object),表示該類是從哪個類繼承下來的,通常,如果沒有合適的繼承類,就使用object類,這是所有類最終都會繼承的類。

class Student(object):
  pass

3.創(chuàng)建實(shí)例后可以自由地給一個實(shí)例變量綁定屬性,比如,給實(shí)例bart綁定一個name屬性,和靜態(tài)語言不同,Python允許對實(shí)例變量綁定任何數(shù)據(jù),也就是說,對于兩個實(shí)例變量,雖然它們都是同一個類的不同實(shí)例,但擁有的變量名稱都可能不同:

>>> bart = Student('Bart Simpson', 59)
>>> lisa = Student('Lisa Simpson', 87)
>>> bart.age = 8
>>> bart.age
8
>>> lisa.ageTraceback (most recent call last): File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'

4.python的__init__方法相當(dāng)于c++或java的類構(gòu)造方法,但跟它們又有些許不同,java的構(gòu)造方法名等于其類名,而python的統(tǒng)一就叫__init__
5.__init__方法的第一個參數(shù)永遠(yuǎn)是self,表示創(chuàng)建的實(shí)例本身,因此,在__init__方法內(nèi)部,就可以把各種屬性綁定到self,因?yàn)閟elf就指向創(chuàng)建的實(shí)例本身。有了__init__方法,在創(chuàng)建實(shí)例的時候,就不能傳入空的參數(shù)了,必須傳入與__init__方法匹配的參數(shù),但self不需要傳,Python解釋器自己會把實(shí)例變量傳進(jìn)去:

class Student(object): 
  def __init__(self, name, score): 
    self.name = name self.score = score
bart = Student('Bart Simpson', 59)
print( bart.name)
#'Bart Simpson'
print(bart.score)
#59

6.多態(tài)

1.多態(tài)的好處就是,當(dāng)我們需要傳入Dog、Cat、Tortoise……時,我們只需要接收Animal類型就可以了,因?yàn)镈og、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會自動調(diào)用實(shí)際類型的run()方法,這就是多態(tài)的意思:

2.對于一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調(diào)用run()方法,而具體調(diào)用的run()方法是作用在Animal、Dog、Cat還是Tortoise對象上,由運(yùn)行時該對象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用方只管調(diào)用,不管細(xì)節(jié),而當(dāng)我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調(diào)用的。這就是著名的“開閉”原則:

對擴(kuò)展開放:允許新增Animal子類;

對修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。

3.對于靜態(tài)語言(例如Java)來說,如果需要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類,否則,將無法調(diào)用run()
方法。對于Python這樣的動態(tài)語言來說,則不一定需要傳入Animal
類型。我們只需要保證傳入的對象有一個run()
方法就可以了:

class Timer(object): 
  def run(self): 
    print('Start...')

這就是動態(tài)語言的“鴨子類型”,它并不要求嚴(yán)格的繼承體系,一個對象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。Python的“file-like object“就是一種鴨子類型。對真正的文件對象,它有一個read()方法,返回其內(nèi)容。但是,許多對象,只要有read()方法,都被視為“file-like object“。許多函數(shù)接收的參數(shù)就是“file-like object“,你不一定要傳入真正的文件對象,完全可以傳入任何實(shí)現(xiàn)了read()方法的對象。

7.獲取對象信息

1.使用type()函數(shù)可以得到對象的類型,它可以判斷基本類型、函數(shù)和類,判斷的時候返回的是該類型對應(yīng)的類的名字,如

>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>
>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False

2.可以使用isinstance()來判斷一個對象是否屬于某種類型的,如:

>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True

并且還可以判斷一個變量是否是某些類型中的一種,比如下面的代碼就可以判斷是否是list或者tuple:

>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True

3.如果要獲得一個對象的所有屬性和方法,可以使用dir()函數(shù),它返回一個包含字符串的list,比如,獲得一個str對象的所有屬性和方法:

>>> dir('ABC')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

4.使用hasattr(),setattr()和getattr()方法可以判斷、設(shè)置和獲取對象的屬性

>>> hasattr(obj, 'x') # 有屬性'x'嗎?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
False
>>> setattr(obj, 'y', 19) # 設(shè)置一個屬性'y'
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
True
>>> getattr(obj, 'y') # 獲取屬性'y'
19
>>> obj.y # 獲取屬性'y'
19

5.type()和isinstance()的區(qū)別
type()和isinstance()都能用來判斷數(shù)據(jù)類型,并且type()能做的工作isinstance()都能做,但是type()不能判斷類的繼承關(guān)系,而isinstance()可以,如

class Foo(object):
  pass

class Bar(Foo):
  pass

print (type(Foo()) == Foo
print (type(Bar()) ==Foo
print(isinstance(Bar(),Foo))
輸出
True
False
True

8.MethodType方法詳細(xì)分析

運(yùn)行如下的代碼

from types import MethodType
def set_age(self,age):
self.age=age
class Stu(object):
  pass
Stu.set_age=MethodType(set_age,Stu)
A=Stu()
A.set_age(10)
print(A.age,B.age)#結(jié)果都是10
B=Stu()
B.set_age(15)
print(A.age,B.age)#結(jié)果都是15

顯然之后的

B.set_age(15)

使得A和B的age屬性都變成了15,同時沒進(jìn)行運(yùn)算的B的age屬性也變了,這時候我推測是對B的age寫入覆蓋了A的age屬性。(但是這個推測有問題,因?yàn)锽并未進(jìn)行運(yùn)算)
隨后運(yùn)行如下的代碼

from types import MethodType
def set_age(self,age):
self.age=age
class Stu(object):
  pass
Stu.set_age=MethodType(set_age,Stu)
A=Stu()
A.set_age(10)
B=Stu()
print(A.age,B.age)#結(jié)果都是10

這意味的,B在沒有進(jìn)行如下運(yùn)算的情況下

B.set_age(10)

仍然獲得了age屬性。
那么我之前的覆蓋推測是錯的。
接下來運(yùn)行如下代碼。

from types import MethodType
def set_age(self,age):
self.age=age
class Stu(object):
pass
Stu.set_age=MethodType(set_age,Stu)
A=Stu()
B=Stu()
A.set_age(10)
print(id(A.age))#獲得A.age的內(nèi)存地址
B.set_age(15)
print(id(A.age),id(B.age))#獲得A.age和B.age的內(nèi)存地址

結(jié)果再運(yùn)行

A.set_age(10)

之后,顯示A.age的地址為XXXXXXXXX。
而在運(yùn)行

B.set_age(15)

之后,A.age的地址發(fā)生了改變,同時B.age的地址與A.age地址一樣。
所以,這里A和B的age值其實(shí)是同一個值。

參見python幫助文檔對MethodType的解釋

help(MethodType)
Help on class method in module builtins:

class method(object)
| method(function, instance)
|
| Create a bound instance method object.

關(guān)于MethodType的用法是這樣說明的:
method(function, instance)
另外有說明"Create a bound instance method object.":創(chuàng)建一個綁定方法的實(shí)例。

而在

Stu.set_age=MethodType(set_age,Stu)

填入的實(shí)例是"Stu"這個類
這意味著所有的屬于Stu這個類的的實(shí)例會全部受到Stu.set_age的影響
同時

Stu.set_age=MethodType(set_age,Stu)

中的"Stu.set_age"根本不重要,只是名字罷了,根本起不到對每個實(shí)例綁定的方法的作用。
運(yùn)行如下代碼測試

from types import MethodType
def set_age(self,age):
self.age=age
class Stu(object):
pass
TEST=MethodType(set_age,Stu)
A=Stu()
B=Stu()
TEST(10)
print(A.age,B.age)#結(jié)果都是10
TEST(15)
print(A.age,B.age)#結(jié)果都是15

那么推測是對的,MethodType前的名稱對MethodType的生效范圍沒有任何影響。
而當(dāng)用

Stu.set_age = set_age

替換

Stu.set_age=MethodType(set_age,Stu)


代碼變成這樣

from types import MethodType
def set_age(self,age):
self.age=age
class Stu(object):
  pass
Stu.set_age = set_age
A=Stu()
B=Stu()
A.set_age(10)
B.set_age(15)
print(A.age,B.age)#結(jié)果為10 15

顯然的,這里"Stu.set_age"的Stu是可以有效的指定到不同的實(shí)例的。

結(jié)論:MethodType只能用于給實(shí)例綁定方法。
當(dāng)使用MethodType給類綁定方法時,方法是指定到類本身的,換而言之,綁定的方法成為了類本身的一個屬性,會影響到整個類,類中的所有元素都會受到影響,獲得此屬性(包括之后加入此類的)。

9.__slots__

參考:
python__slots__

10.@property

@property
廣泛應(yīng)用在類的定義中,可以讓調(diào)用者寫出簡短的代碼,同時保證對參數(shù)進(jìn)行必要的檢查,這樣,程序運(yùn)行時就減少了出錯的可能性。

class Student(object): 
  @property 
  def score(self): 
    return self._score 
  @score.setter 
  def score(self, value): 
    if not isinstance(value, int): 
      raise ValueError('score must be an integer!') 
    if value < 0 or value > 100: 
      raise ValueError('score must between 0 ~ 100!') 
    self._score = value

我們在對實(shí)例屬性操作的時候,就知道該屬性很可能不是直接暴露的,而是通過getter和setter方法來實(shí)現(xiàn)的。

還可以定義只讀屬性,只定義getter方法,不定義setter方法就是一個只讀屬性:

class Student(object): 
  @property 
  def birth(self): 
    return self._birth 
  @birth.setter 
  def birth(self, value):
    self._birth = value 
  @property 
  def age(self): 
    return 2015 - self._birth
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容