Python的基礎進階
Python的基礎進階
1、函式
- 函式的定義
- 函式的呼叫
- 函式文件
- 函式引數
- 函式的返回值
- 變數作用域
2、Lambda-表示式
- 匿名函式定義
- 匿名函式的應用
3、類與物件
- 屬性和方法組成物件
- self是什麼
- Python的魔法方法
- 共有和私用
- 繼承
- 組合
- 類、類物件和例項物件
- 什麼是繫結
- 一些相關的內建函式
4、魔法方法
- 基本的魔法方法
- 算數運算子
- 反算數運算子
- 增值賦值運算
- 一元運算子
- 屬性訪問
- 描述符
- 定製序列
- 迭代器
1、函式
1.函式的定義
- 函式以def關鍵詞開頭,後接函式名和圓括號()。
- 函式執行的程式碼以冒號起始,並且縮排。
- return [表示式]結束函式,選擇性地返回一個值給呼叫方。不帶表示式的return相當於返回None。
def functionname (parameters):
"函式_文件字串"
function_suite
return [expression]
2.函式的呼叫
【例子】
def printme(str):
print(str)
printme("我要呼叫使用者自定義函式!") # 我要呼叫使用者自定義函式!
printme("再次呼叫同一函式") # 再次呼叫同一函式
temp = printme('hello') # hello
print(temp) # None
3.函式文件
def MyFirstFunction(name):
"函式定義過程中name是形參"
# 因為Ta只是一個形式,表示佔據一個引數位置
print('傳遞進來的{0}叫做實參,因為Ta是具體的引數值!'.format(name))
MyFirstFunction('老馬的程式人生')
# 傳遞進來的老馬的程式人生叫做實參,因為Ta是具體的引數值!
print(MyFirstFunction.__doc__)
# 函式定義過程中name是形參
help(MyFirstFunction)
# Help on function MyFirstFunction in module __main__:
# MyFirstFunction(name)
# 函式定義過程中name是形參
4.函式引數
- 位置引數 (positional argument)
- 預設引數 (default argument)
- 可變引數 (variable argument)
- 關鍵字引數 (keyword argument)
- 命名關鍵字引數 (name keyword argument)
- 引數組合
1.位置引數
def functionname(arg1):
"函式_文件字串"
function_suite
return [expression]
- arg1 - 位置引數 ,這些引數在呼叫函式 (call function) 時位置要固定
2.預設引數
def functionname(arg1, arg2=v):
"函式_文件字串"
function_suite
return [expression]
- arg2 = v - 預設引數 = 預設值,呼叫函式時,預設引數的值如果沒有傳入,則被認為是預設值。
- 預設引數一定要放在位置引數後面,不然程式會報錯。
【例子】
def printinfo(name, age=8):
print('Name:{0},Age:{1}'.format(name, age))
printinfo('小馬') # Name:小馬,Age:8
printinfo('小馬', 10) # Name:小馬,Age:10
- Python 允許函式呼叫時引數的順序與宣告時不一致,因為 Python 直譯器能夠用引數名匹配引數值。
【例子】
def printinfo(name, age):
print('Name:{0},Age:{1}'.format(name, age))
printinfo(age=8, name='小馬') # Name:小馬,Age:8
3.可變引數
- 可變引數就是傳入的引數個數是可變的,可以是 0, 1, 2 到任意個,是不定長的引數。
def functionname(arg1, arg2=v, *args):
"函式_文件字串"
function_suite
return [expression]
- *args - 可變引數,可以是從零個到任意個,自動組裝成元組。
- 加了星號(*)的變數名會存放所有未命名的變數引數。
【例子】
def printinfo(arg1, *args):
print(arg1)
for var in args:
print(var)
printinfo(10) # 10
printinfo(70, 60, 50)
# 70
# 60
# 50
4.關鍵字引數
def functionname(arg1, arg2=v, args, **kw):
"函式_文件字串"
function_suite
return [expression]
- **kw - 關鍵字引數,可以是從零個到任意個,自動組裝成字典。
【例子】
def printinfo(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
printinfo(70, 60, 50)
# 70
# (60, 50)
# {}
printinfo(70, 60, 50, a=1, b=2)
# 70
# (60, 50)
# {'a': 1, 'b': 2}
「可變引數」和「關鍵字引數」的同異總結:
- 可變引數允許傳入零個到任意個引數,它們在函式呼叫時自動組裝為一個元組 (tuple)。
- 關鍵字引數允許傳入零個到任意個引數,它們在函式內部自動組裝為一個字典 (dict)。
5.命名關鍵字引數
def functionname(arg1, arg2=v, args, *, nkw, *kw):
"函式_文件字串"
function_suite
return [expression]
- *, nkw - 命名關鍵字引數,使用者想要輸入的關鍵字引數,定義方式是在nkw 前面加個分隔符 *。
- 如果要限制關鍵字引數的名字,就可以用「命名關鍵字引數」
- 使用命名關鍵字引數時,要特別注意不能缺少引數名。
【例子】
def printinfo(arg1, *, nkw, **kwargs):
print(arg1)
print(nkw)
print(kwargs)
printinfo(70, nkw=10, a=1, b=2)
# 70
# 10
# {'a': 1, 'b': 2}
printinfo(70, 10, a=1, b=2)
# TypeError: printinfo() takes 1 positional argument but 2 were given
- 沒有寫引數名nwk,因此 10 被當成「位置引數」,而原函式只有 1 個位置函式,現在呼叫了 2 個,因此程式會報錯。
6.引數組合
在 Python 中定義函式,可以用位置引數、預設引數、可變引數、命名關鍵字引數和關鍵字引數,這 5 種引數中的 4 個都可以一起使用,但是注意,引數定義的順序必須是:
- 位置引數、預設引數、可變引數和關鍵字引數。
- 位置引數、預設引數、命名關鍵字引數和關鍵字引數。
要注意定義可變引數和關鍵字引數的語法:
- *args 是可變引數,args 接收的是一個 tuple
- **kw 是關鍵字引數,kw 接收的是一個 dict
命名關鍵字引數是為了限制呼叫者可以傳入的引數名,同時可以提供預設值。定義命名關鍵字引數不要忘了寫分隔符 *,否則定義的是位置引數。
5.函式的返回值
【例子】
def add(a, b):
return a + b
print(add(1, 2)) # 3
print(add([1, 2, 3], [4, 5, 6])) # [1, 2, 3, 4, 5, 6]
【例子】
def back():
return [1, '小馬的程式人生', 3.14]
print(back()) # [1, '小馬的程式人生', 3.14]
6.變數作用域
- Python 中,程式的變數並不是在哪個位置都可以訪問的,訪問許可權決定於這個變數是在哪裡賦值的。
- 定義在函式內部的變數擁有區域性作用域,該變數稱為區域性變數。
- 定義在函式外部的變數擁有全域性作用域,該變數稱為全域性變數。
- 區域性變數只能在其被宣告的函式內部訪問,而全域性變數可以在整個程式範圍內訪問。
【例子】
def discounts(price, rate):
final_price = price * rate
return final_price
old_price = float(input('請輸入原價:')) # 98
rate = float(input('請輸入折扣率:')) # 0.9
new_price = discounts(old_price, rate)
print('打折後價格是:%.2f' % new_price) # 88.20
- 當內部作用域想修改外部作用域的變數時,就要用到global和nonlocal關鍵字了。
【例子】
num = 1
def fun1():
global num # 需要使用 global 關鍵字宣告
print(num) # 1
num = 123
print(num) # 123
fun1()
print(num) # 123
內嵌函式
【例子】
def outer():
print('outer函式在這被呼叫')
def inner():
print('inner函式在這被呼叫')
inner() # 該函式只能在outer函式內部被呼叫
outer()
# outer函式在這被呼叫
# inner函式在這被呼叫
閉包
- 是函數語言程式設計的一個重要的語法結構,是一種特殊的內嵌函式。
- 如果在一個內部函式裡對外層非全域性作用域的變數進行引用,那麼內部函式就被認為是閉包。
- 通過閉包可以訪問外層非全域性作用域的變數,這個作用域稱為
閉包作用域。
【例子】
def funX(x):
def funY(y):
return x * y
return funY
i = funX(8)
print(type(i)) # <class 'function'>
print(i(5)) # 40
【例子】閉包的返回值通常是函式。
def make_counter(init):
counter = [init]
def inc(): counter[0] += 1
def dec(): counter[0] -= 1
def get(): return counter[0]
def reset(): counter[0] = init
return inc, dec, get, reset
inc, dec, get, reset = make_counter(0)
inc()
inc()
inc()
print(get()) # 3
dec()
print(get()) # 2
reset()
print(get()) # 0
【例子】 如果要修改閉包作用域中的變數則需要 nonlocal 關鍵字
def outer():
num = 10
def inner():
nonlocal num # nonlocal關鍵字宣告
num = 100
print(num)
inner()
print(num)
outer()
# 100
# 100
【例子】如果一個函式在內部呼叫自身本身,這個函式就是遞迴函式。
# 利用迴圈
n = 5
for k in range(1, 5):
n = n * k
print(n) # 120
# 利用遞迴
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
【例子】斐波那契數列 f(n)=f(n-1)+f(n-2), f(0)=0 f(1)=1
# 利用迴圈
i = 0
j = 1
lst = list([i, j])
for k in range(2, 11):
k = i + j
lst.append(k)
i = j
j = k
print(lst)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# 利用遞迴
def recur_fibo(n):
if n <= 1:
return n
return recur_fibo(n - 1) + recur_fibo(n - 2)
lst = list()
for k in range(11):
lst.append(recur_fibo(k))
print(lst)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
2、Lambda 表示式
1.匿名函式的定義
在 Python 裡有兩類函式:
- 第一類:用 def 關鍵詞定義的正規函式
- 第二類:用 lambda 關鍵詞定義的匿名函式
Python 使用 lambda 關鍵詞來建立匿名函式,而非def關鍵詞,它沒有函式名,其語法結構如下:
lambda argument_list: expression
- lambda - 定義匿名函式的關鍵詞。
- argument_list -函式引數,它們可以是位置引數、預設引數、關鍵字引數,和正規函式裡的引數型別一樣。
- :- 冒號,在函式引數和表示式中間要加個冒號。
- expression - 只是一個表示式,輸入函式引數,輸出一些值。
注意:
- expression 中沒有 return 語句,因為 lambda 不需要它來返回,表示式本身結果就是返回值。
- 匿名函式擁有自己的名稱空間,且不能訪問自己引數列表之外或全域性名稱空間裡的引數。
【例子】
def sqr(x):
return x ** 2
print(sqr)
# <function sqr at 0x000000BABD3A4400>
y = [sqr(x) for x in range(10)]
print(y)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
lbd_sqr = lambda x: x ** 2
print(lbd_sqr)
# <function <lambda> at 0x000000BABB6AC1E0>
y = [lbd_sqr(x) for x in range(10)]
print(y)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
sumary = lambda arg1, arg2: arg1 + arg2
print(sumary(10, 20)) # 30
func = lambda *args: sum(args)
print(func(1, 2, 3, 4, 5)) # 15
2.匿名函式的應用
- 函數語言程式設計是指程式碼中每一塊都是不可變的,都由純函式的形式組成。這裡的純函式,是指函式本身相互獨立、互不影響,對於相同的輸入,總會有相同的輸出,沒有任何副作用。
【例子】非函數語言程式設計
def f(x):
for i in range(0, len(x)):
x[i] += 10
return x
x = [1, 2, 3]
f(x)
print(x)
# [11, 12, 13]
匿名函式 常常應用於函數語言程式設計的高階函式 (high-order function)中,主要有兩種形式:
- 引數是函式 (filter, map)
- 返回值是函式 (closure)
如,在 filter和map函式中的應用:
- filter(function, iterable) 過濾序列,過濾掉不符合條件的元素,返回一個迭代器物件,如果要轉換為列表,可以使用
list() 來轉換。
【例子】
odd = lambda x: x % 2 == 1
templist = filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(templist)) # [1, 3, 5, 7, 9]
- map(function, *iterables) 根據提供的函式對指定序列做對映。
m1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(list(m1))
# [1, 4, 9, 16, 25]
m2 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(list(m2))
# [3, 7, 11, 15, 19]
3、類與物件
1.物件 = 屬性 + 方法
物件是類的例項。換句話說,類主要定義物件的結構,然後我們以類為模板建立物件。類不但包含方法定義,而且還包含所有例項共享的資料。
- 封裝:資訊隱蔽技術
我們可以使用關鍵字 class 定義 Python 類,關鍵字後面緊跟類的名稱、分號和類的實現。
【例子】
class Turtle: # Python中的類名約定以大寫字母開頭
"""關於類的一個簡單例子"""
# 屬性
color = 'green'
weight = 10
legs = 4
shell = True
mouth = '大嘴'
# 方法
def climb(self):
print('我正在很努力的向前爬...')
def run(self):
print('我正在飛快的向前跑...')
def bite(self):
print('咬死你咬死你!!')
def eat(self):
print('有得吃,真滿足...')
def sleep(self):
print('困了,睡了,晚安,zzz')
tt = Turtle()
print(tt)
# <__main__.Turtle object at 0x0000007C32D67F98>
print(type(tt))
# <class '__main__.Turtle'>
print(tt.__class__)
# <class '__main__.Turtle'>
print(tt.__class__.__name__)
# Turtle
tt.climb()
# 我正在很努力的向前爬...
tt.run()
# 我正在飛快的向前跑...
tt.bite()
# 咬死你咬死你!!
# Python類也是物件。它們是type的例項
print(type(Turtle))
# <class 'type'>
- 繼承:子類自動共享父類之間資料和方法的機制
【例子】
class MyList(list):
pass
lst = MyList([1, 5, 2, 7, 8])
lst.append(9)
lst.sort()
print(lst)
# [1, 2, 5, 7, 8, 9]
- 多型:不同物件對同一方法響應不同的行動
【例子】
class Animal:
def run(self):
raise AttributeError('子類必須實現這個方法')
class People(Animal):
def run(self):
print('人正在走')
class Pig(Animal):
def run(self):
print('pig is walking')
class Dog(Animal):
def run(self):
print('dog is running')
def func(animal):
animal.run()
func(Pig())
# pig is walking
2.self 是什麼
- Python 的 self 相當於 C++ 的 this 指標。
【例子】
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
# <__main__.Test object at 0x000000BC5A351208>
# <class '__main__.Test'>
- 類的方法與普通的函式只有一個特別的區別 —— 它們必須有一個額外的第一個引數名稱(對應於該例項,即該物件本身),按照慣例它的名稱self。在呼叫方法時,我們無需明確提供與引數 self 相對應的引數。
【例子】
class Ball:
def setName(self, name):
self.name = name
def kick(self):
print("我叫%s,該死的,誰踢我..." % self.name)
a = Ball()
a.setName("球A")
b = Ball()
b.setName("球B")
c = Ball()
c.setName("球C")
a.kick()
# 我叫球A,該死的,誰踢我...
b.kick()
# 我叫球B,該死的,誰踢我...
Python 的魔法方法
- 類有一個名為__init__(self[, param1, param2…])的魔法方法,該方法在類例項化時會自動呼叫。
【例子】
class Ball:
def __init__(self, name):
self.name = name
def kick(self):
print("我叫%s,該死的,誰踢我..." % self.name)
a = Ball("球A")
b = Ball("球B")
c = Ball("球C")
a.kick()
# 我叫球A,該死的,誰踢我...
b.kick()
# 我叫球B,該死的,誰踢我...
4.公有和私有
- 在 Python 中定義私有變數只需要在變數名或函式名前加上“__”兩個下劃線,那麼這個函式或變數就會為私有的了。
【例子】類的私有屬性例項
class JustCounter:
__secretCount = 0 # 私有變數
publicCount = 0 # 公開變數
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count() # 1
counter.count() # 2
print(counter.publicCount) # 2
# Python的私有為偽私有
print(counter._JustCounter__secretCount) # 2
print(counter.__secretCount)
# AttributeError: 'JustCounter' object has no attribute '__secretCount'
【例子】類的私有方法例項
class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private
def who(self):
print('name : ', self.name)
print('url : ', self.__url)
def __foo(self): # 私有方法
print('這是私有方法')
def foo(self): # 公共方法
print('這是公共方法')
self.__foo()
x = Site('老馬的程式人生', 'https://blog.csdn.net/LSGO_MYP')
x.who()
# name : 老馬的程式人生
# url : https://blog.csdn.net/LSGO_MYP
x.foo()
# 這是公共方法
# 這是私有方法
x.__foo()
# AttributeError: 'Site' object has no attribute '__foo'
5.繼承
- Python 同樣支援類的繼承,派生類的定義如下所示:
class DerivedClassName(BaseClassName):
statement-1
.
.
.
statement-N
- BaseClassName(基類名)必須與派生類定義在一個作用域內。除了類,還可以用表示式,基類定義在另一個模組中時這一點非常有用:
class DerivedClassName(modname.BaseClassName):
statement-1
.
.
.
statement-N
【例子】如果子類中定義與父類同名的方法或屬性,則會自動覆蓋父類對應的方法或屬性。
# 類定義
class people:
# 定義基本屬性
name = ''
age = 0
# 定義私有屬性,私有屬性在類外部無法直接進行訪問
__weight = 0
# 定義構造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 說: 我 %d 歲。" % (self.name, self.age))
# 單繼承示例
class student(people):
grade = ''
def __init__(self, n, a, w, g):
# 呼叫父類的構函
people.__init__(self, n, a, w)
self.grade = g
# 覆寫父類的方法
def speak(self):
print("%s 說: 我 %d 歲了,我在讀 %d 年級" % (self.name, self.age, self.grade))
s = student('小馬的程式人生', 10, 60, 3)
s.speak()
# 小馬的程式人生 說: 我 10 歲了,我在讀 3 年級
6.組合
【例子】
class Turtle:
def __init__(self, x):
self.num = x
class Fish:
def __init__(self, x):
self.num = x
class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池裡面有烏龜%s只,小魚%s條" % (self.turtle.num, self.fish.num))
p = Pool(2, 3)
p.print_num()
# 水池裡面有烏龜2只,小魚3條
8.什麼是繫結
- Python 嚴格要求方法需要有例項才能被呼叫,這種限制其實就是 Python 所謂的繫結概念。
- Python 物件的資料屬性通常儲存在名為.__ dict__的字典中,我們可以直接訪問__dict__,或利用 Python的內建函式vars()獲取.__ dict__。
【例子】
class CC:
def setXY(self, x, y):
self.x = x
self.y = y
def printXY(self):
print(self.x, self.y)
dd = CC()
print(dd.__dict__)
# {}
print(vars(dd))
# {}
print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
dd.setXY(4, 5)
print(dd.__dict__)
# {'x': 4, 'y': 5}
print(vars(CC))
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
9.一些相關的內建函式(BIF)
- issubclass(class, classinfo) 方法用於判斷引數 class 是否是型別引數 classinfo 的子類。
- 一個類被認為是其自身的子類。
- classinfo可以是類物件的元組,只要class是其中任何一個候選類的子類,則返回True。
【例子】
class A:
pass
class B(A):
pass
print(issubclass(B, A)) # True
print(issubclass(B, B)) # True
print(issubclass(A, B)) # False
print(issubclass(B, object)) # True
- isinstance(object, classinfo) 方法用於判斷一個物件是否是一個已知的型別,類似type()。
- type()不會認為子類是一種父類型別,不考慮繼承關係。
- isinstance()會認為子類是一種父類型別,考慮繼承關係。
如果第一個引數不是物件,則永遠返回False。
如果第二個引數不是類或者由類物件組成的元組,會丟擲一個TypeError異常。
【例子】
a = 2
print(isinstance(a, int)) # True
print(isinstance(a, str)) # False
print(isinstance(a, (str, int, list))) # True
class A:
pass
class B(A):
pass
print(isinstance(A(), A)) # True
print(type(A()) == A) # True
print(isinstance(B(), A)) # True
print(type(B()) == A) # False
- hasattr(object, name)用於判斷物件是否包含對應的屬性。
【例子】
class Coordinate:
x = 10
y = -5
z = 0
point1 = Coordinate()
print(hasattr(point1, 'x')) # True
print(hasattr(point1, 'y')) # True
print(hasattr(point1, 'z')) # True
print(hasattr(point1, 'no')) # False
- getattr(object, name[, default])用於返回一個物件屬性值。
【例子】
class A(object):
bar = 1
a = A()
print(getattr(a, 'bar')) # 1
print(getattr(a, 'bar2', 3)) # 3
print(getattr(a, 'bar2'))
# AttributeError: 'A' object has no attribute 'bar2'
- setattr(object, name, value)對應函式 getattr(),用於設定屬性值,該屬性不一定是存在的。
【例子】
class A(object):
bar = 1
a = A()
print(getattr(a, 'bar')) # 1
setattr(a, 'bar', 5)
print(a.bar) # 5
setattr(a, "age", 28)
print(a.age) # 28
- delattr(object, name)用於刪除屬性。
【例子】
class Coordinate:
x = 10
y = -5
z = 0
point1 = Coordinate()
print('x = ', point1.x) # x = 10
print('y = ', point1.y) # y = -5
print('z = ', point1.z) # z = 0
delattr(Coordinate, 'z')
print('--刪除 z 屬性後--') # --刪除 z 屬性後--
print('x = ', point1.x) # x = 10
print('y = ', point1.y) # y = -5
# 觸發錯誤
print('z = ', point1.z)
# AttributeError: 'Coordinate' object has no attribute 'z'
- class property([fget[, fset[, fdel[, doc]]]])用於在新式類中返回屬性值。
- fget --獲取屬性值的函式
- fset – 設定屬性值的函式
- fdel – 刪除屬性值函式
- doc – 屬性描述資訊
【例子】
class C(object):
def __init__(self):
self.__x = None
def getx(self):
return self.__x
def setx(self, value):
self.__x = value
def delx(self):
del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")
cc = C()
cc.x = 2
print(cc.x) # 2
del cc.x
print(cc.x)
# AttributeError: 'C' object has no attribute '_C__x'
4、魔法方法
- 魔法方法總是被雙下劃線包圍,例如__init__。
- 魔法方法是物件導向的 Python 的一切,如果你不知道
- 魔法方法,說明你還沒能意識到物件導向的 Python 的強大。
- 魔法方法的“魔力”體現在它們總能夠在適當的時候被自動呼叫。
- 魔法方法的第一個引數應為cls(類方法) 或者self(例項方法)。
cls:代表一個類的名稱
self:代表一個例項物件的名稱
1.基本的魔法方法
- init(self[, …]) 構造器,當一個例項被建立的時候呼叫的初始化方法
【例子】
class Rectangle:
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self):
return (self.x + self.y) * 2
def getArea(self):
return self.x * self.y
rect = Rectangle(4, 5)
print(rect.getPeri()) # 18
print(rect.getArea()) # 20
- new_(cls[, …]) 在一個物件例項化的時候所呼叫的第一個方法,在呼叫__init__初始化前,先呼叫__new__
- new__至少要有一個引數cls,代表要例項化的類,此引數在例項化時由 Python 直譯器自動提供,後面的引數直接傳遞給__init。
- new__對當前類進行了例項化,並將例項返回,傳給__init__的self。但是,執行了__new,並不一定會進入__init__,只有__new__返回了,當前類cls的例項,當前類的__init__才會進入。
【例子】
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(cls, *args, **kwargs)
b = B(10)
# 結果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.B'>
# into B __init__
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(A, *args, **kwargs) # 改動了cls變為A
b = B(10)
# 結果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.A'>
- 若__new__沒有正確返回當前類cls的例項,那__init__是不會被呼叫的,即使是父類的例項也不行,將沒有__init__被呼叫。
【例子】利用__new__實現單例模式。
class Earth:
pass
a = Earth()
print(id(a)) # 260728291456
b = Earth()
print(id(b)) # 260728291624
class Earth:
__instance = None # 定義一個類屬性做判斷
def __new__(cls):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
a = Earth()
print(id(a)) # 512320401648
b = Earth()
print(id(b)) # 512320401648
- __new__方法主要是當你繼承一些不可變的 class 時(比如int, str, tuple), 提供給你一個自定義這些類的例項化過程的途徑。
【例子】
class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)
a = CapStr("i love lsgogroup")
print(a) # I LOVE LSGOGROUP
- del(self) 析構器,當一個物件將要被系統回收之時呼叫的方法。
【例子】
class C(object):
def __init__(self):
print('into C __init__')
def __del__(self):
print('into C __del__')
c1 = C()
# into C __init__
c2 = c1
c3 = c2
del c3
del c2
del c1
# into C __del__
- str(self):
- 當你列印一個物件的時候,觸發__str__
- 當你使用%s格式化的時候,觸發__str__
- str強轉資料型別的時候,觸發__str__
- repr(self):
- repr是str的備胎
- 有__str__的時候執行__str__,沒有實現__str__的時候,執行__repr__
- repr(obj)內建函式對應的結果是__repr__的返回值
- 當你使用%r格式化的時候 觸發__repr__
【例子】
class Cat:
"""定義一個貓類"""
def __init__(self, new_name, new_age):
"""在建立完物件之後 會自動呼叫, 它完成物件的初始化的功能"""
self.name = new_name
self.age = new_age
def __str__(self):
"""返回一個物件的描述資訊"""
return "名字是:%s , 年齡是:%d" % (self.name, self.age)
def __repr__(self):
"""返回一個物件的描述資訊"""
return "Cat:(%s,%d)" % (self.name, self.age)
def eat(self):
print("%s在吃魚...." % self.name)
def drink(self):
print("%s在喝可樂..." % self.name)
def introduce(self):
print("名字是:%s, 年齡是:%d" % (self.name, self.age))
# 建立了一個物件
tom = Cat("湯姆", 30)
print(tom) # 名字是:湯姆 , 年齡是:30
print(str(tom)) # 名字是:湯姆 , 年齡是:30
print(repr(tom)) # Cat:(湯姆,30)
tom.eat() # 湯姆在吃魚....
tom.introduce() # 名字是:湯姆, 年齡是:30
- str(self) 的返回結果可讀性強。也就是說,str 的意義是得到便於人們閱讀的資訊,就像下面的 ‘2019-10-11’ 一樣。
- repr(self) 的返回結果應更準確。怎麼說,repr 存在的目的在於除錯,便於開發者使用。
【例子】
import datetime
today = datetime.date.today()
print(str(today)) # 2019-10-11
print(repr(today)) # datetime.date(2019, 10, 11)
print('%s' %today) # 2019-10-11
print('%r' %today) # datetime.date(2019, 10, 11)
2.算術運算子
- 型別工廠函式,指的是“不通過類而是通過函式來建立物件”。
【例子】
class C:
pass
print(type(len)) # <class 'builtin_function_or_method'>
print(type(dir)) # <class 'builtin_function_or_method'>
print(type(int)) # <class 'type'>
print(type(list)) # <class 'type'>
print(type(tuple)) # <class 'type'>
print(type(C)) # <class 'type'>
print(int('123')) # 123
# 這個例子中list工廠函式把一個元祖物件加工成了一個列表物件。
print(list((1, 2, 3))) # [1, 2, 3]
- add(self, other)定義加法的行為:+
- sub(self, other)定義減法的行為:-
【例子】
class MyClass:
def __init__(self, height, weight):
self.height = height
self.weight = weight
# 兩個物件的長相加,寬不變.返回一個新的類
def __add__(self, others):
return MyClass(self.height + others.height, self.weight + others.weight)
# 兩個物件的寬相減,長不變.返回一個新的類
def __sub__(self, others):
return MyClass(self.height - others.height, self.weight - others.weight)
# 說一下自己的引數
def intro(self):
print("高為", self.height, " 重為", self.weight)
def main():
a = MyClass(height=10, weight=5)
a.intro()
b = MyClass(height=20, weight=10)
b.intro()
c = b - a
c.intro()
d = a + b
d.intro()
if __name__ == '__main__':
main()
# 高為 10 重為 5
# 高為 20 重為 10
# 高為 10 重為 5
# 高為 30 重為 15
- mul(self, other)定義乘法的行為:*
- truediv(self, other)定義真除法的行為:/
- floordiv(self, other)定義整數除法的行為://
- mod(self, other) 定義取模演算法的行為:%
- divmod(self, other)定義當被 divmod() 呼叫時的行為 divmod(a, b)把除數和餘數運算結果結合起來,返回一個包含商和餘數的元組(a // b, a % b)。
【例子】
print(divmod(7, 2)) # (3, 1)
print(divmod(8, 2)) # (4, 0)
- pow(self, other[, module])定義當被 power() 呼叫或 ** 運算時的行為
- lshift(self, other)定義按位左移位的行為:<<
- rshift(self, other)定義按位右移位的行為:>>
- and(self, other)定義按位與操作的行為:&
- xor(self, other)定義按位異或操作的行為:^
- or(self, other)定義按位或操作的行為:|
3.反算術運算子
反運算魔方方法,與算術運算子保持一一對應,不同之處就是反運算的魔法方法多了一個“r”。當檔案左操作不支援相應的操作時被呼叫。
- radd(self, other)定義加法的行為:+
- rsub(self, other)定義減法的行為:-
- rmul(self, other)定義乘法的行為:*
- rtruediv(self, other)定義真除法的行為:/
- rfloordiv(self, other)定義整數除法的行為://
- rmod(self, other) 定義取模演算法的行為:%
- rdivmod(self, other)定義當被 divmod() 呼叫時的行
- rpow(self, other[, module])定義當被 power() 呼叫或 ** 運算時的行為
- rlshift(self, other)定義按位左移位的行為:<<
- rrshift(self, other)定義按位右移位的行為:>>
- rand(self, other)定義按位與操作的行為:&
- rxor(self, other)定義按位異或操作的行為:^
- ror(self, other)定義按位或操作的行為:|
【例子】
class Nint(int):
def __radd__(self, other):
return int.__sub__(other, self) # 注意 self 在後面
a = Nint(5)
b = Nint(3)
print(a + b) # 8
print(1 + b) # -2
4.增量賦值運算子
- iadd(self, other)定義賦值加法的行為:+=
- isub(self, other)定義賦值減法的行為:-=
- imul(self, other)定義賦值乘法的行為:*=
- itruediv(self, other)定義賦值真除法的行為:/=
- ifloordiv(self, other)定義賦值整數除法的行為://=
- imod(self, other)定義賦值取模演算法的行為:%=
- ipow(self, other[, modulo])定義賦值冪運算的行為:**=
- ilshift(self, other)定義賦值按位左移位的行為:<<=
- irshift(self, other)定義賦值按位右移位的行為:>>=
- iand(self, other)定義賦值按位與操作的行為:&=
- ixor(self, other)定義賦值按位異或操作的行為:^=
- ior(self, other)定義賦值按位或操作的行為:|=
5.一元運算子
- neg(self)定義正號的行為:+x
- pos(self)定義負號的行為:-x
- abs(self)定義當被abs()呼叫時的行為
- invert(self)定義按位求反的行為:~x
6.屬性訪問
- getattr(self, name): 定義當使用者試圖獲取一個不存在的屬性時的行為。
- getattribute(self, name):定義當該類的屬性被訪問時的行為(先呼叫該方法,檢視是否存在該屬性,若不存在,接著去呼叫__getattr__)。
- setattr(self, name, value):定義當一個屬性被設定時的行為。
- delattr(self, name):定義當一個屬性被刪除時的行為。
7.描述符
描述符就是將某種特殊型別的類的例項指派給另一個類的屬性。
- get(self, instance, owner)用於訪問屬性,它返回屬性的值。
- set(self, instance, value)將在屬性分配操作中呼叫,不返回任何內容。
- del(self, instance)控制刪除操作,不返回任何內容。
【例子】
class MyDecriptor:
def __get__(self, instance, owner):
print('__get__', self, instance, owner)
def __set__(self, instance, value):
print('__set__', self, instance, value)
def __delete__(self, instance):
print('__delete__', self, instance)
class Test:
x = MyDecriptor()
t = Test()
t.x
# __get__ <__main__.MyDecriptor object at 0x000000CEAAEB6B00> <__main__.Test object at 0x000000CEABDC0898> <class '__main__.Test'>
t.x = 'x-man'
# __set__ <__main__.MyDecriptor object at 0x00000023687C6B00> <__main__.Test object at 0x00000023696B0940> x-man
del t.x
# __delete__ <__main__.MyDecriptor object at 0x000000EC9B160A90> <__main__.Test object at 0x000000EC9B160B38>
8.定製序列
協議(Protocols)與其它程式語言中的介面很相似,它規定你哪些方法必須要定義。然而,在 Python 中的協議就顯得不那麼正式。事實上,在 Python 中,協議更像是一種指南。
容器型別的協議
- 如果說你希望定製的容器是不可變的話,你只需要定義__len__()和__getitem__()方法。
- 如果你希望定製的容器是可變的話,除了__len__()和__getitem__()方法,你還需要定義__setitem__()和__delitem__()兩個方法。
【例子】編寫一個不可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
return len(self.values)
def __getitem__(self, item):
self.count[item] += 1
return self.values[item]
c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1]) # 3
print(c2[2]) # 6
print(c1[1] + c2[1]) # 7
print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}
- len(self)定義當被len()呼叫時的行為(返回容器中元素的個數)
- getitem(self, key)定義獲取容器中元素的行為,相當於self[key]。
- setitem(self, key, value)定義設定容器中指定元素的行為,相當於self[key] = value。
- delitem(self, key)定義刪除容器中指定元素的行為,相當於del self[key]。
【例子】編寫一個可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
return len(self.values)
def __getitem__(self, item):
self.count[item] += 1
return self.values[item]
def __setitem__(self, key, value):
self.values[key] = value
def __delitem__(self, key):
del self.values[key]
for i in range(0, len(self.values)):
if i >= key:
self.count[i] = self.count[i + 1]
self.count.pop(len(self.values))
c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1]) # 3
print(c2[2]) # 6
c2[2] = 12
print(c1[1] + c2[2]) # 15
print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}
del c1[1]
print(c1.count)
# {0: 0, 1: 0, 2: 0, 3: 0}
9.迭代器
- 迭代是 Python 最強大的功能之一,是訪問集合元素的一種方式。
- 迭代器是一個可以記住遍歷的位置的物件。
- 迭代器物件從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。
- 迭代器只能往前不會後退。 字串,列表或元組物件都可用於建立迭代器:
【例子】
string = 'lsgogroup'
for c in string:
print(c)
'''
l
s
g
o
g
r
o
u
p
'''
for c in iter(string):
print(c)
- 迭代器有兩個基本的方法:iter() 和 next()。
- iter(object) 函式用來生成迭代器。
- next(iterator[,default]) 返回迭代器的下一個專案。
- iterator – 可迭代物件
- default --可選,用於設定在沒有下一個元素時返回該預設值,如果不設定,又沒有下一個元素則會觸發 StopIteration 異常。
【例子】
links = {'B': '百度', 'A': '阿里', 'T': '騰訊'}
it = iter(links)
while True:
try:
each = next(it)
except StopIteration:
break
print(each)
# B
# A
# T
it = iter(links)
print(next(it)) # B
print(next(it)) # A
print(next(it)) # T
print(next(it)) # StopIteration
把一個類作為一個迭代器使用需要在類中實現兩個魔法方法 iter() 與 next() 。
- iter(self)定義當迭代容器中的元素的行為,返回一個特殊的迭代器物件, 這個迭代器物件實現了
- next() 方法並通過 StopIteration 異常標識迭代的完成。next() 返回下一個迭代器物件。
- StopIteration 異常用於標識迭代的完成,防止出現無限迴圈的情況,在 next() 方法中我們可以設定在完成指定迴圈次數後觸發 StopIteration 異常來結束迭代。
【例子】
class Fibs:
def __init__(self, n=10):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIteration
return self.a
fibs = Fibs(100)
for each in fibs:
print(each, end=' ')
# 1 1 2 3 5 8 13 21 34 55 89
生成器
- 在 Python 中,使用了 yield 的函式被稱為生成器(generator)。
- 跟普通函式不同的是,生成器是一個返回迭代器的函式,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。
- 在呼叫生成器執行的過程中,每次遇到yield 時函式會暫停並儲存當前所有的執行資訊,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續執行。
- 呼叫一個生成器函式,返回的是一個迭代器物件。
【例子】
def myGen():
print('生成器執行!')
yield 1
yield 2
myG = myGen()
for each in myG:
print(each)
'''
生成器執行!
1
2
'''
myG = myGen()
print(next(myG))
# 生成器執行!
# 1
print(next(myG)) # 2
print(next(myG)) # StopIteration
相關文章
- 【python基礎】input函式的基礎使用以及進階Python函式
- 零基礎Python學習路線,小白的進階之路!Python
- Python文字統計與分析從基礎到進階Python
- Scanner的進階使用——基礎計算
- 前端基礎之jQuery進階前端jQuery
- 【Go進階—基礎特性】反射Go反射
- 【Go進階—基礎特性】deferGo
- 【Go進階—基礎特性】介面Go
- Pandas進階貳 pandas基礎
- SpringCloud基礎教程(三)-Eureka進階SpringGCCloud
- 【Go進階—基礎特性】錯誤Go
- 【深度學習基礎-12】多元迴歸分析基礎及進階-python程式碼實現深度學習Python
- js基礎進階–從ajax到fetch的理解JS
- 4、JavaScript進階篇①——基礎語法JavaScript
- 前端基礎入門六(JQuery進階)前端jQuery
- 【Go進階—基礎特性】定時器Go定時器
- Scala菜鳥進階之路一 基礎
- 前端進階 -- 微信小程式基礎前端微信小程式
- 【Go進階—基礎特性】panic 和 recoverGo
- python基礎中的基礎Python
- Python進階Python
- Airbnb資料工程師的進階指南:技術基礎AI工程師
- 長沙Java培訓:Java基礎通往高階進階篇Java
- 給Python學習者的檔案讀寫指南(含基礎與進階,建議收藏)Python
- Java基礎14-java進階(5)【IO流】Java
- 2019 JavaScript面試題詳解(基礎+進階)JavaScript面試題
- 現代IT基礎設施管理(2):Terraform進階ORM
- 跟著老貓來搞GO,基礎進階Go
- 資料恢復基礎和進階教程(二)資料恢復
- Python函式的進階Python函式
- Python基礎篇-Python基礎01Python
- Python進階 — matplotlibPython
- Python進階之道Python
- Python進階 -- matplotlibPython
- 輕鬆學 dva(基礎 + 進階)(32 個視訊)
- EOS基礎全家桶(十五)智慧合約進階2
- Python3影片零基礎進階高階運維Django爬蟲專案實戰2017全套教程Python運維Django爬蟲
- js基礎進階–promise和setTimeout執行順序的問題JSPromise