Python入門細節

python入門細節

相除後的類型

type(2/2)
float
type(2//2)
int

雙斜槓是整除,出來的類型是int。單斜槓的出來的是float類型。java

進製表示和轉換

進製表示:python

  • 二進制:0b
  • 八進制:0o
  • 十六進制:0x

進制轉換:c++

  • 轉換爲二進制:bin()
  • 轉換爲八進制:oct()
  • 轉換爲十進制:int()
  • 轉換爲十六進制:hex()
  • 轉換爲布爾類型:bool()

布爾類型

布爾類型轉換:bool()windows

  1. 布爾類型屬於數字這個基本數據類型裏面
  2. 只要是非零的數字,bool類型的值爲True
  3. 對於字符串,布爾類型爲True,除了空字符串
  4. bool值爲False:
  • bool(0)
  • bool('') 中間沒有空格
  • bool([])
  • bool({})
  • bool(None)
  • bool(NoneType)
  • bool(set{})

多行字符串

三個引號能夠再IDLE下回車不會執行換行。print函數能夠輸出n這樣的反義字符。
單個引號想回車換行能夠再前面加上字符便可。數組

'''
sadasdj
adas
'''
Out[1]: '\nsadasdj\nadas\n'

'asda
  File "<ipython-input-2-6af9d7d5e65d>", line 1
    'asda
         ^
SyntaxError: EOL while scanning string literal


'asdd\
adsad\
sad'
Out[3]: 'asddadsadsad'

print('asda\nsada\n')
asda
sada


'''
asda\n
'''
Out[5]: '\nasda\n\n'

原始字符串

原始字符串在print時只是輸出裏面的字符,不考慮反義之類的,當心r大寫R都沒有關係。app

print(r'c:\nsda\nsds')
c:\nsda\nsds

print(r'let's go')
  File "<ipython-input-3-a81b31c0c433>", line 1
    print(r'let's go')
                ^
SyntaxError: invalid syntax

字符串的運算

1.字符串的'+'和'*'函數

"hello"+"world"
Out[1]: 'helloworld'

"hello"*3
Out[2]: 'hellohellohello'

2.獲取字符串裏的字符ui

"hello world"[0]
Out[3]: 'h'

"hello world"[-1]
Out[4]: 'd'

# 包括左面可是不包括右面
"hello world"[0:4]
Out[5]: 'hell'

"hello world"[0:-1]
Out[6]: 'hello worl'

# 超出長度時會按字符串最大的長度進行截取
"hello world"[0:20]
Out[7]: 'hello world'
# 沒有右邊的值的時候,表示直接輸出到末尾
"hello world"[6:]
Out[8]: 'world'
# 負數在冒號前面的時候
"hello world"[-4:]
Out[9]: 'orld'

python表示序列的方式

1.列表(list)

  • 列表中的元素能夠是任意類型的組合,好比列表的嵌套,布爾類型,字符串等等。

1.1 基本操做
1.1.1 基本選取(切片)this

["新月打擊","蒼白之瀑","月之降臨","月神衝刺"]
Out[10]: ['新月打擊', '蒼白之瀑', '月之降臨', '月神衝刺']

["新月打擊","蒼白之瀑","月之降臨","月神衝刺"][0]
Out[11]: '新月打擊'

["新月打擊","蒼白之瀑","月之降臨","月神衝刺"][0:2]
Out[12]: ['新月打擊', '蒼白之瀑']

["新月打擊","蒼白之瀑","月之降臨","月神衝刺"][-1:]
Out[13]: ['月神衝刺']


a = [1,2,3,4,5,6,7,8]
print(a[0:3])
print(a[0:len(a):2])
print(a[len(a):0:-2])

[1, 2, 3]
[1, 3, 5, 7]
[8, 6, 4, 2]

#能夠看到,切片操做很簡單,第二個冒號後面的數字能夠看做是步長。注意負數時的用法。

能夠看到,當沒有冒號的時候,單個選取出的是元素的類型。可是當有冒號的時候,選取出的是序列的類型。這裏須要注意debug

1.1.2 列表的相加和乘法

["新月打擊","蒼白之瀑","月之降臨","月神衝刺"]+['虛弱','點燃']
Out[14]: ['新月打擊', '蒼白之瀑', '月之降臨', '月神衝刺', '虛弱', '點燃']

['虛弱','點燃']*3
Out[15]: ['虛弱', '點燃', '虛弱', '點燃', '虛弱', '點燃']

1.1.3 判斷元素是否存在

  • 運用in和not in便可
3 in [1,2,3,4]
Out[21]: True

3 not in [1,2,3,4]
Out[22]: False

1.1.4 計算長度,最大小值

len([1,2,3])
Out[23]: 3

len("hesadad")
Out[24]: 7

max([1,2,3,4,5,6])
Out[25]: 6

min([1,2,3,4])
Out[26]: 1

1.1.5 append()
能夠向列表中追加元素。

a = [1,2,3,4]

a.append('5')

Out[22]: [1, 2, 3, 4, '5']

2.元組(tuple)

  • 元組的操做,包括訪問,加,乘,in等操做和列表是相同的。
  • 須要注意一點是:
type((1))
Out[16]: int

type(('sd'))
Out[17]: str

type((1,2,3))
Out[18]: tuple

若是括號裏有一個元素,默認爲是一個運算,不會認爲是元組的括號。若是要定義只有一個元素的元組的:

type((1,))
Out[19]: tuple
# 括號裏面什麼都沒有表示一個空元組
type(())
Out[20]: tuple
  • 元組是序列,不可變類型,可是若是元組裏包含了列表,好比:
a = (1,2,3,[4,5])

a[3][1] = '2'

print(a)
(1, 2, 3, [4, '2'])

咱們能夠看到元組裏的列表能夠改變

3.字符串(str)

  • 字符串和元組都是不可變的類型
  • 序列包括了字符串,列表和元組,序列均可以用下標索引和切片的方式。

set集合

  • set集合裏的元素是無序的,不重複的。
  • in,not in,len,max,min,可是沒有加,乘這種操做。
  • 集合有相減,交集,並集等操做
{1,2,3,4,5,6} - {1,2}
Out[1]: {3, 4, 5, 6}

{1,2,3,4,5,6} & {1,2}
Out[2]: {1, 2}

{1,2,3,4,5,6} | {1,2,7}
Out[3]: {1, 2, 3, 4, 5, 6, 7}
  • 定義一個空集合的方法:set()
type({})
Out[8]: dict

type(set())
Out[9]: set

len(set())
Out[10]: 0

字典(dict)

  • 字典和集合類型(set)有些相似,裏面是無序的,因此字典不是序列。
  • 字典中能夠value可使任意類型;可是key是能夠的,key必須是不可變的類型,好比Int,str,tuple等,例如list就是不能夠的。
  • 字典的訪問:{'key1':'value1,'key2':'value2'}['key1'],字典的訪問經過key來進行
  • 字典裏,key值是不能夠重複的,若是定義有重複雖然不會報錯,可是會自動選擇其中一個。
  • 序列,集合和字典屬於組,是Python的基本數據類型。

變量

  • 變量的定義時,首字母不能是數字,但能夠是下劃線。字母,數組,下劃線能夠組成變量。
  • Python 變量名區分大小寫。定義變量的時候不用指明類型,和C++不同。
  • 值類型和引用類型
a = 1

b = a

a = 3

print(b)
1

a = [1,2,3,4]

b = a

a[0] = '1'

print(b)
['1', 2, 3, 4]

值類型:int str tuple(不可改變),在從新定義的時候,由於不可改變會生成一個新的對象,這個時候b仍然指向原對象,a指向了一個新對象
引用類型:list,set,dict(能夠改變),在定義一個新對象的時候,會在原對象的基礎上進行改變而不產生新對象,因此不管是a仍是b都會指向已經改變的原對象,因此a和b的值都會變化。

再進一步的,能夠看如下代碼:
a = 'hello'

id(a)
Out[15]: 1510080259608

a = a + 's'

id(a)
Out[17]: 1510081716832

a[0] = 's'
Traceback (most recent call last):

  File "<ipython-input-18-02436d67df37>", line 1, in <module>
    a[0] = 's'

TypeError: 'str' object does not support item assignment
id()是查詢在計算機中的內存位置,咱們能夠看到發生了變化。因此a = a + 's'是能夠的。可是對字符串的賦值操做,是不能夠的,由於str是不可變的類型。

運算符

  • python中是沒有自增和自減這種操做的。
  • 表示「等於」是'==',「不等於」是'!='
  • 字符串相比較的時候,把字符串中每個字符拿出來相比較,比較AscII碼值
  • 比較兩個列表,和字符串是相同的。元組也能夠進行比較,和列表和字符串是相同的。
  • 非bool類型在參與邏輯運算的時候,好比int,float,str等類型,在參與and,or,not的時候,遵循的規則和c++中相似。
0 and 1
Out[1]: 0

1 and 2
Out[2]: 2

1 and 0
Out[3]: 0

1 or 2
Out[4]: 1

0 or 1
Out[5]: 1

由上面的例子咱們能夠看出and和or的邏輯判斷規則和c++一致。空字符串,0等判斷爲空,在上面的筆記中有記載。

  • 成員運算符: in, not in

成員運算符表示一個元素是否在一個組裏;成員運算符返回值類型是bool類型。在字典中,是判斷key值。

a = 1

a in {1:'1'}
Out[7]: True

a = '1'

a in {1:'1'}
Out[9]: False
  • 身份運算符

is, is not
身份運算符比較的是身份而不是值,簡單來講就是內存地址。和關係運算符「==」不同。

a = 1

b = 1

a is b
Out[12]: True

id(a)
Out[13]: 1438837200

id(b)
Out[14]: 1438837200

b = 1.0

a is b
Out[16]: False

id(b)
Out[17]: 2197963106536

a ==b
Out[18]: True

a = {1,2,3}

b = {2,1,3}

a==b
Out[21]: True

a is b
Out[22]: False

c = (1,2,3)

d = (2,1,3)

c ==d
Out[25]: False

c is d
Out[26]: False

id(a)
Out[27]: 2197907160424

id(b)
Out[28]: 2197990760232

咱們能夠看到,在無序的set集合中,元素順序不同在內存中位置不一樣,雖然值相同可是身份仍然不同。

  • 位運算符

&, |, ^, ~, <<, >>
以上都是把數字看成二進制進行運算。把數字按照二進制進行換算,以&舉例,相同位1,不一樣爲0。而後再把二進制數轉換成數字原來的進制。eg: 2&3 == 2

判斷變量的類型

python中一切都是對象,對象有三大特徵,值(value), 身份(id), 類型(type)。判斷變量的類型,可使用isinstance()這個函數。

a = 'sds'

isinstance(a,str)
Out[30]: True

isinstance(a,(str,int,float))
Out[31]: True

isinstance(a,int)
Out[32]: False

isinstance能夠判斷對象中的子類是否知足條件,因此比較好。

vscode python 基本操做

+ 單行註釋:# 快捷鍵:ctrl + /
+ 多行註釋:""" """ 快捷鍵:alt + shift + a

pylint

  • 每一個文件(模塊)須要有開篇的註釋來講明做用。
  • python中不存在常量(constant)一說,可是對於形式上的常量,通常以所有大寫來表示
  • Python變量中兩個名字的銜接用下劃線,eg:test_account.

python包和模塊

注意事項

  • 包和模塊是不會被重複導入的。
  • 儘可能避免循環引入。
  • 導入一個模塊的時候,會執行這個模塊裏面的代碼。
python中的普通模塊必須有一個包,當想要把一個可執行文件看成一個普通模塊運行時,可使用-m參數,如:
python -m 命名空間.模塊名
注意:此處若看成普通模塊,必須包括包名/命名空間。python中可執行文件沒有所屬包。此外,當使用-m參數後,頂級包也相對改變。

dir函數

用來查看模塊或者類內部的變量,包括系統內置變量。

import sys
infos = dir(sys)
print(infos)


['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding',......]

# 可見打出了許多的變量,是sys模塊內部的變量。下面的代碼中也有應用,只不過沒有參數。

__name__的應用技巧

if __name__ == '__main__':
    pass

#來判斷模塊是否被看成入口文件被調用,若是被當作模塊就不會打印if條件成立執行的語句,若是被當作入口文件纔會執行

1.模塊導入的方法

# 由父包引入子包或者同級別引入的狀況

import module  # 只能引入同一個包(不包括子包)裏的模塊。注意這裏不能直接引入模塊的變量。

import module as name  # 使用的時候name.變量/函數等。

from packet import module # 能夠父包裏的子包引入模塊。

from packet.module import module.變量/函數等 

from module import *  # 引入module內__all__指定的變量/函數等。

from module import module.變量1, module.變量2,......  # 引入多個變量可用逗號隔開

2.__init__.py

該文件,能夠在導入一個包,或者導入包中的函數的時候,系統會首先執行該文件。

from packet import *  # 這行代碼會引入被引入包中__init__.py中__all__指定的模塊。

3.模塊內置變量

a = 2
b = 1
infos = dir()
print(infos)

['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']

# 上方除了'a','b'都是系統內置的變量。

下面介紹幾個比較重要的內置變量,利用import一個模塊的時候會執行該模塊裏面的內容的機制。對於入口文件和模塊文件,內置變量的值有所不一樣。

  • 模塊文件
'''
this is a c3 doc
'''
print("name: "+__name__)
print("package: "+__package__)
print("doc: "+__doc__)
print("flie: "+__file__)

import sub11.c3

PS D:\pycode\sub1> python c2.py
name: sub11.c3
package: sub11
doc:
this is a c3 doc

flie: D:\pycode\sub1\sub11\c3.py

# __doc__記錄的是該模塊的開頭註釋

# __name__記錄該模塊的名字

# __package__記錄該模塊屬於的包

# __file__記錄該模塊的文件的絕對路徑
  • 入口文件

若是一個.py文件被當作一個應用程序的入口:
①它的名稱再也不是自己的模塊名稱,而是被強制更改成__main__
②它不屬於任何包
③file內置變量不會像普通模塊同樣顯示絕對路徑,它所顯示的值也不是肯定值,和執行命令所在目錄有關
注:python入口文件和普通導入的模塊文件是有差別的。

'''
this is a c3 doc
'''
print("name: "+__name__)
print("package: "+ ( __package__ or "當前模塊不屬於任何包"))
print("doc: "+__doc__)
print("flie: "+__file__)



name: __main__
package: 當前模塊不屬於任何包
doc:
this is a c3 doc

flie: c3.py

# 該文件屬於sub11包(有__init__.py這個文件),可是咱們是直接執行的c3.py文件,可見此時若是在c3.py中打印內置變量,__name__被強制定位__main__,並且package上也不會顯示出所屬於的包,file路徑也發生了變化。

4.絕對導入和相對導入

導入機制:

  • python模塊導入時的搜索路徑:

    1. 程序主目錄,執行程序是包含執行代碼文件的目錄,交互模式下爲當前工做目錄,優先級最高
    2. PYTHONPATH中的目錄
    3. 標準連接庫目錄,就是python的安裝目錄,源碼在裏面
    4. 3.x 中能夠用.pth 文件
  • 以上這些構成了sys.path。你寫的模塊存儲路徑在sys.path 裏面就能夠import。
  • 絕對導入是指從入口文件引入執行文件所在的文件夾的包中的模塊的時候,須要進行絕對導入。from ... import...中若是沒有出現.模塊名,也是絕對導入。
  • 相對導入指從模塊引入父級的模塊時,須要進行相對導入。在入口文件切記不能使用相對導入,即帶.號。好比你單獨運行某個模塊,可是在這個模塊裏你用了相對導入,那麼就會報錯。可是你在外面引入這個模塊的時候是不存在問題的。
  • 注意在模塊下面,最好不要有和模塊名重名的文件。
  1. 頂級包與入口文件main.py的位置有關,與main.py同級的包就是該包下全部模塊的頂級包。而對於入口文件來講不存在包的概念。
  2. 絕對導入/絕對路徑:從頂級包到被導入模塊名稱的完整路徑。注意必定是完整的路徑。
  3. 相對導入,一個'.'表示當前包,兩個'..'表示上一級包.'...'上上級包,以此類推。

注意:

  • import不支持相對導入,只能使用from import格式實現相對導入。
  • 入口文件中不能使用相對導入,由於它沒有包的概念。
  • 使用相對導入不要超出頂級包,和入口文件同級都不能使用相對導入
  • pycharm中,你打開一個工程,你的入口文件處的sys.path中會自動添加該工程中的目錄,因此假設你在模塊a中相對引入其餘模塊b,模塊b所在的位置超過了你如今所運行的文件(入口文件)所在的位置,可是隻要不超過當前的工程目錄所在的位置,仍然能夠進行相對導入。

函數

注意事項

  • python默認有一個遞歸次數限制來防止無限遞歸調用,但能夠設置遞歸最大次數:
import sys
sys.setrecursionlimit(10000)
# 能夠設置最大迭代10000次。不過理論上雖然設置這麼多,但實際上仍然達不到容許迭代這麼屢次。
  • python中for循環內定義的變量能夠在外部使用,這點和c和java不相同。
  • 若函數體中沒有返回值,則認爲返回None。

1.return 返回多個值,鏈式賦值和序列解包

python函數返回多個值直接在return後面用逗號分隔要返回的值便可,返回結果是tuple元組類型。比較好的接收函數返回的多個值的方法不是用一個變量接收元組而後用序號訪問它的元素,而是直接用多個值接收而後分別使用這些變量,如:

def damage(skill1, skill2)
    damage1 = skll1 * 3
    damage2 = skill2 * 3 + 10
    return damage1, damage2
    
skill1_damage, skill2_damage = damage(3, 6)
print(skill1_danage, skill2_damage)

上面的接受參數的方式叫作序列解包。

  • 鏈式賦值和序列解包
d = 1, 2, 3
print(type(d))
a, b, c = d
print(a, b, c)
print('----------------')
a = b = c = 1
print(a, b, c)

<class 'tuple'>
1 2 3
----------------
1 1 1

由於是序列解包,因此能夠不是元組,列表也是能夠的。最後若是多個變量取同一個值,那麼能夠用上面的方法來進行賦值。

2.函數參數

函數參數有:

  • 必須參數:形參和實參。
  • 關鍵字參數
  • 默認參數
  • 可變參數
  • 可變參數能夠解開可變,而且能夠進行可變關鍵字參數。定義可變參數後,傳值的時候能夠什麼都不傳,這個時候是空元組或者空字典。
def demo(*param):
    print(param)
    print(type(param))

demo(1,2,3,[4,5,6])

(1, 2, 3, [4, 5, 6])
<class 'tuple'>

# 傳入可變參數,會定義爲元組。

def demo(*param):
    print(param)
    print(type(param))

a = 1,2,3
demo(a)
demo(*a)

((1, 2, 3),)
<class 'tuple'>
(1, 2, 3)
<class 'tuple'>

# *能夠解包。

def demo(**param):
    print(param)
    print(type(param))

demo(q='萬能牌', w='切牌', e='占卜')

{'q': '萬能牌', 'w': '切牌', 'e': '占卜'}
<class 'dict'>

# 可見傳進來之後是一個字典,很方便。這就是關鍵字可變參數。

def demo(**param):
    print(param)
    print(type(param))
    for key,value in param.items():
        print(key,':',value,end='|| ')

demo(q='萬能牌', w='切牌', e='占卜')

{'q': '萬能牌', 'w': '切牌', 'e': '占卜'}
<class 'dict'>
q : 萬能牌|| w : 切牌|| e : 占卜||

# 傳入字典時能夠採用上面的方式取出鍵值和內容。

def demo(**param):
    print(param)
    print(type(param))
    for key,value in param.items():
        print(key,':',value,end='|| ')

a = {'q':'萬能牌', 'w':'切牌', 'e':'占卜'}
demo(**a)

{'q': '萬能牌', 'w': '切牌', 'e': '占卜'}
<class 'dict'>
q : 萬能牌|| w : 切牌|| e : 占卜||

# 和傳入元組同樣,解序列能夠傳入兩個*。
  • 形參是定義函數的時候定義的參數,實參是調用函數的時候傳遞的參數。
  • 關鍵字參數經過指定形參來進行參數賦值。
  • 可變參數在必須參數以後,默認參數以前,不然會出現賦值的錯誤
def demo(param1,param2 = 2,*param3):
    print(param1)
    print(param2)
    print(param3)
    
demo('a', 1,2,3)

a
1
(2, 3)

# 可見若是默認參數在可變參數以前,會發生錯誤,和預想的(1,2,3)賦值給param3有區別。

---------------------------------------------------------------------------

# 調整一下順序能夠獲得想要的結果

def f1(name1, *args, name2='2', **kw):
    print(name1)
    print(name2)
    print(args)
    print(kw)
f1('1','3','4',a='1',b='2')


1
2
('3', '4')
{'a': '1', 'b': '2'}

注意事項

  • 類名最好不要用下劃線,有多個單詞的時候能夠採用大寫首字母的方法。
  • 類的最基本做用就是封裝。定義類,實例化對象
  • 類只負責定義和刻畫,並不負責去執行代碼。因此在類裏面去執行方法是不正確的。
  • 在一個模塊裏面,不要既定義類,又去實例化類執行代碼。
  • 不要把類和模塊搞混,類裏面有本身的規則

1.構造函數

  • 構造函數即__init__(self):
  • 實例化類的時候構造函數被自動執行
  • 構造函數返回值爲None ,不能人爲return更改。
  • 能夠經過類名.__init__()來執行構造函數。

2.類變量和實例變量

  • 類變量是定義在類內可是不在__init__()中;實例變量是定義在___init__()中的。換句話說,實例變量是對象的,類變量是類的,兩者不能混淆。
  • python中,類與對象的變量查找是有順序的。
class Student():
    name = 'Catherian'
    age = 0
    high = 170
    def __init__(self, name, age, high):
        self.name = name
        self.age = age
        high = high
        # 注意這裏的身高沒有用self.high來定義
    
    def doHomework(self):
        print('doHomework')

student1 = Student('呵呵噠', 18, 180)
student2 = Student('ojbk', 16, 175)
print(student1.name, student1.age, student1.high)
print(student2.name, student2.age, student2.high)
print(Student.name, Student.age, Student.high)
print(student1.__dict__)
print(Student.__dict__)



呵呵噠 18 170 

ojbk 16 170

Catherian 0 170  # 這裏打印出的纔是類變量

# 能夠看到,儘管咱們在實例化student1,student2的時候傳入了身高high這個數據,可是打印的時候咱們發現輸出的是類變量high,並非實例變量。

{'name': '呵呵噠', 'age': 18}

# __dict__對與對象,打印出的是對象的實例變量。可見裏面並無high。因此實例變量是用 self. 來定義的。類的__dict__是打印出對象裏面的內容,包括數據成員和方法,下面便是

{'__module__': '__main__', 'name': 'Catherian', 'age': 0, 'high': 170, '__init__': <function Student.__init__ at 0x000001F06B70F9D8>, 'doHomework': <function Student.doHomework at 0x000001F06B70FA60>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

雖然咱們在實例化對象時傳入了數據,可是咱們發現high是類變量不是實例變量,可是仍然sudent1.high打印出了變量,這是類變量而不是實例變量。這是由於,python中的查找機制:當查找實例變量不存在的時候,會繼續向上查找類中相對應的類變量,若是子類中沒有父類中有(出現繼承)時,會查找到父類。因此咱們打印出了類變量。

3.實例方法

  • python中,實例方法的參數裏必需要顯式的定義出self,但在外部調用的時候不須要給出self。self指的就是你在外部實例化的對象。因此self.給出的是實例變量。
  • 在實例方法中調用實例變量最好用self.的形式來進行調用。由於你傳入的是形參.
  • 在實例方法中調用類變量有兩種方法:類名.類變量self.__class__.類變量

4.類方法

  • 定義類方法:
class Student
    sum = 0
    @classmethod
    def student_sum(cls):
        pass
    
# cls能夠更換,函數上面是一個裝飾器,表示了這是一個類方法。cls換成self或者其餘任意的都是能夠的,和實例方法中self能夠任意替換別的字符是同樣的。

對於類方法,調用類變量:cls.類變量 便可。因此cls表明的就是所屬於的類。在調用類方法的時候,能夠 Student.studen_sum 也能夠經過對象來調用,即:student1.student_sum。可是建議用類名來調用比較好。

5.靜態方法

  • 定義靜態方法:
class Student
    sum = 0
    @staticmethod
    def add(x,y)
        pass

靜態方法上一樣要有裝飾器來修飾,可是函數中不用顯式的傳入self或者cls,更像是一個普通的函數。在類方法和靜態方法中都不能調用實例變量。通常不建議用靜態方法,類方法更方便。

6.成員可見性

在python中,實際上沒有什麼是不能訪問的。成員可見性更像是一種標誌,一切全靠自覺。定義私有變量或者方法的時候,只須要在變量或者方法前面加上雙下劃線就表明了私有(注意不要同時在後面再加上雙下劃線)

# 咱們定義一個學生類

class Student():
    name = 'Catherian'
    age = 0
    __high = 170
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__score = 0
    
    def __doHomework(self):
        print('doHomework')
        

student1 = Student('呵呵噠', 18)
print(student1.__score)

Traceback (most recent call last):
  File "c1.py", line 15, in <module>
    print(student1.__score)
AttributeError: 'Student' object has no attribute '__score'
# 能夠看到不能這樣訪問。
---------------------------------------------------------------------

# 若是咱們再加上一句再執行:

student1 = Student('呵呵噠', 18)
student1.__score = -1
print(student1.__score)

-1

# 咱們發現居然能夠成功賦值而且訪問的。這是由於 studen1.__score = -1 這個操做實際上是又定義了一個新的實例變量。咱們能夠打印看一下

student1 = Student('okk', 18)
student1.__score = -1
# print(student1.__score)
print(student1.__dict__)


{'name': 'okk', 'age': 18, '_Student__score': 0, '__score': -1}

# 咱們能夠看到,咱們再裏面定義的__score變量被定義成了_Student__score變量,__score變量是咱們根據Python動態特性新定義出的實例變量。因此要訪問私有變量也很簡單:

print(student1._Student__score)

0

# 因此這個真的全靠自覺,python中沒什麼是不能訪問的。

7.繼承性

python中能夠單繼承也能夠多繼承。

  • 子類繼承父類,會繼承父類中的變量(類變量和實例變量都會繼承)和父類中的方法。
  • 在子類內部,若是有和父類重名的變量,會按照咱們在類變量和實例變量中說明的搜索規則進行。
  • 若是有重名的方法,想在子類內部進行調用,能夠採用super(子類名, self)進行調用父類重名函數。
  • 在python中,能夠用類名調用實例方法。很奇怪可是是能夠的。
  • 在子類構造函數中,經過傳入多個參數,調用父類構造函數便可完成初始化。
  • 多繼承容易出現BUG。
# 定義一個Human父類
class Human():
    sum = 0
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__class__.sum += 1
    def get_name(self):
        print(self.name)
    def do_Homework(self):   # 重名的方法
        print("this is a parent method")
        
# 定義一個子類Student

from c2 import Human
class Student(Human):
    sum = 0  # 和父類重名的類變量
    def __init__(self, name, age, score):  # 父類還有兩個參數,因此這裏有三個參數
       Human.__init__(self, name, age)  # 這裏注意經過類名調用方法,不能不加self
       self.score = score 
       self.__class__.sum += 1
    def do_Homework(self):  # 和父類重名的方法。
        super(Student, self).do_Homework()
        print('doHomework')

student1 = Student('okk', 18, 61)
print(student1.sum)
print(Student.sum)
print(student1.get_name())
print(student1.do_Homework())


2   # 可見經過父類方法裏對sum的操做,繼承到子類中時,對於重名變量仍然能夠操做子類中的重名變量。
2  # 根據搜索機制,實例變量裏沒有找到子類裏的類變量,再沒有找父類。
okk
None
this is a parent method # 可見調用了父類中的方法。
doHomework
None

枚舉

python中的枚舉類型實際上是一個類。

from enum import Enum

class diamond(Enum):  # 必需要繼承父類Enum
    YELLOW = 1
    BLUE = 2
    GREEN = 3
    RED = 4
print(diamond.YELLOW)


diamond.YELLOW

# 可見打印出的就是diamend.YELLOW
  • 在枚舉類型中,每一個類型有不一樣的值,不容許出現相同類型賦不一樣值,值能夠是任意類型的。若是出現了兩個枚舉類型的值相同,下面的枚舉類型會被當成是上面枚舉類型的別名。
from enum import Enum

class diamond(Enum):
    YELLOW = 1
    BLUE = 1
    GREEN = 3
    RED = 4
    
print(diamond.BLUE)
print(diamond.__members__.items()) # items()能夠不須要。打印出全部的枚舉類型。


diamond.YELLOW # 可打印的是BLUE出來的是YEELOW。
odict_items([('YELLOW', <diamond.YELLOW: 1>), ('BLUE', <diamond.YELLOW: 1>), ('GREEN', <diamond.GREEN: 3>), ('RED', <diamond.RED: 4>)])
  • 不能在類的外部修改類型的值,好比diamond.YELLOW = 5是會報錯的。
  • 類型最好用大寫表示,表示爲常量不能修改。
  • 枚舉類型,枚舉名稱,枚舉的值,代碼以下:
from enum import Enum

class diamond(Enum):
    YELLOW = 1
    BLUE = 2
    GREEN = 3
    RED = 4
print("枚舉類型爲:", type(diamond.GREEN), diamond.GREEN)
print("枚舉的名稱爲", type(diamond.GREEN.name), diamond.GREEN.name)
print("枚舉的值爲:", diamond.GREEN.value)

枚舉類型爲: <enum 'diamond'> diamond.GREEN
枚舉的名稱爲 <class 'str'> GREEN
枚舉的值爲: 3
  • 能夠採用for循環得到枚舉類型等:
for i in diamond:
    print(i)
    
diamond.YELLOW
diamond.BLUE
diamond.GREEN
diamond.RED
  • 枚舉類型之間不能作大小的比較,能夠作等值的比較;枚舉類型和枚舉值之間不能作等值的比較;枚舉類型能夠作身份(is)的比較。不一樣枚舉類之間的枚舉類型不能比較。
  • 從枚舉值得到枚舉類型:
class diamond(Enum):
    YELLOW = 1
    BLUE = 2
    GREEN = 3
    RED = 4
a = 1
print(diamond(a))


diamond.YELLOW
# 從一個具體的值得到相應的枚舉類型。頗有用。
  • 若是想要每一個枚舉類型的值都是int類型,能夠引入from enum import IntEnum,在枚舉類的括號裏爲IntEnum
  • 若是不想出現兩個枚舉類型出現同一個值(會報錯),能夠引入一個裝飾器:
from enum import Enum
from enum import IntEnum, unique

@unique # 裝飾器
class diamond(IntEnum):
    YELLOW = 1
    BLUE = 2
    GREEN = 3
    RED = 4
相關文章
相關標籤/搜索