Python封裝

  • 2019 年 10 月 6 日
  • 筆記

Python函數教程

函數本身其實就相當於一個集裝箱,她負責把我們之前寫的那些程式碼裝進去,她在打包的時候會在箱子的上下各開兩個透氣的口子,上面的口子叫參數,下面的口子叫返回值~~~~~(當然你也可以選擇性的關閉這兩個口子哦)

"""

python定義函數, 對程式碼進行封裝,python也是引用傳遞,而不是值傳遞

1- 如果函數名一樣,python並不會報錯,而是會覆蓋

def 函數名(參數)

"""

def my_print():

print("HAHAHHA")

def my_print():

print("HAHAHHA22222")

for i in range(5):

my_print()

# 如果提示shadows in xxx build in是因為你定義的函數名和內置的函數名一樣,比如sum()

def my_sum(a, b):

print("a + b = %d" % (a + b))

my_sum(1,5)

# 帶有返回值的函數, 使用 -> 的方式,和typescript類似

def my_sum(a, b) -> int:

return (a + b)

print("a + b = %d" % my_sum(1, 5))

"""

函數的嵌套調用,就是函數中調用另一個函數

1- my_func02 必須定義在My_func01之前,真正調用的時候才會載入,並不會全局預載入

2- 內置函數的作用域,不會自動調用

"""

def my_func02():

print("C")

print("D")

def my_func01():

print("A")

my_func02()

print("B")

my_func01()

def my_func03():

print("A")

# 內置def函數,注意作用域, 注意內置函數不會自動調用

def my_func04():

print("C")

my_func04()

print("D")

print("B")

my_func03()

# 函數參數的亂序位置,也可以像kotlin一樣添加關鍵字參數

# 注意:如果某個參數使用了關鍵字參數,那麼之後的參數必須都必須使用關鍵字參數

# 換句話說,就是參數可以合理的一一對應,開發中一般很少使用關鍵字參數,看懂即可

def get_info(name, age) -> str:

return "name: %s, age: %s" % (name, age)

print(get_info(age= "26", name="張三"))

"""

預設函數,就是參數可以有默認值,跟kotlin一樣

返回值也可以簡寫,省略 -> int:

"""

def print_info(name, age=20):

print("姓名:%s, 年齡:%s" % (name, age))

print_info("張三", 28)

print_info("李四")

"""

元組[]不定長參數,參數的數量不確定, 調用類似於位置參數

參數名之前加上*表示這個星號表明參數的類型為元祖,但是傳入實參的時候不需要中括弧[]

"""

def my_func01(*args):

print(type(args))

print(args[0])

my_func01(1, 3, 5)

my_func01(1, 3, 5, 7)

"""

字典類型{}的不定長參數, 調用類似於關鍵字參數name=的形式

參數名前面加上**兩個星號,表明這個參數為一個字典,傳入的時候不需要寫{},但是只能傳入一個字典

"""

def my_func02(**kwargs):

print(type(kwargs))

print(kwargs["name"])

print(kwargs["age"])

my_func02(name="小明", age=12)

"""

一個函數的包含多return個

"""

def my_func03(score: int) -> str:

if score >= 70:

return "優秀"

elif score >= 30:

return "中性"

else:

return "差"

print(my_func03(50))

"""

處理多個返回值的方式

1- return ["小明", 28]

2- return {"name":"小明","age":28]

2- return 返回值1, 返回值2

"""

def my_func04(name, age):

return name, age

print(my_func04("張三",28)[0])

print(my_func04("張三",28)[1])

"""

python中的拆包(列表,字典,多個返回值): 一次性初始化多個變數的值

如果返回值是列表,字典,或者多個返回值,可以直接用來賦值多個變數的方式就叫做拆包,簡化程式碼量

"""

num01, num02, num03, num04 = 1, 3.14, True, "Hello World"

num05, num06, num07, num08 = [1, 3.14, True, "Hello World"]

name, age = my_func04("李四", 28)

print(name, "–>", age)

"""

拆包中python快速交換兩個變數的值, 免去了temp中間值

"""

a, b = 4, 5

a, b = b, a # b的引用給a, a的引用給b,快速交換值

"""

函數中的局部變數的釋放獅是在函數執行完後就馬上消失

全局變數是等真箇程式運行完後進行銷毀,作用域是整個函數

1- 如果局部變數名和全局的相同,那麼執行的時候根據就近原則

2- 如果函數內找不到該變數名,那麼就去找全局變數

3- 如果函數內想要就該外面的全局變數,使用globe關鍵字

"""

num = 10

def my_func01():

# num = 20 這裡是創建一個新的內部變數

global num

num = 20 # 這裡告訴函數並非創建新的局部變數,而是使用全局的變數操作

print("內部num = %s" % num)

my_func01()

print("外部num = %s" % num)

"""

函數自建函數文檔說明help(len)

如果函數內沒有自定義文檔說明,那麼就返回找函數名上面一行的注釋

"""

help(len)

# 這裡是沒有專門的說明進行返回的內容

def my_func02(num01, num02):

"""

返回兩個參數的和

:param num01: 數字1

:param num02: 數字2

:return: 兩個數字的和

"""

return num01 + num02

help(my_func02)

"""

id(obj)查找obj記憶體的物理地址引用門牌號

類似:定了一個房間但是沒有入住,調用的時候才入住

a,b指向同一個房間,節省記憶體

"""

a = 1000

b = 1000

c = "abc" # 字元串,元祖()等不可不的數據類型,修改的話是copy重新開一個房間

d = "abc" # 列表[],字典可變數據結構,修改的話是在同一個房間進行修改的。

c = "abcd"

print(id(a))

print(id(b))

print(id(c))

print(id(d))

Python函數—遞歸專欄

這個說起來就比較煩了,簡而言之就是自己用自己。

"""

斐波那契

python中的遞歸函數, time模組中的sleep(單位是秒s)

1- 用現有的while循環來實現

2- 遞歸實現,必須有一個停止的條件來調用自己

"""

"""

原理:

n! = {

if -> n * (n – 1)! if( n>=0)

else -> 1 if( n=0)

}

1- f(3) -> 3*f(2)

2- f(2) -> 2*f(1)

3- f(1) -> 1*f(0)

4- f(0) -> return 1

"""

def c_func(num):

if num > 1:

return num * c_func(num – 1)

else:

return 1

print(c_func(3))

"""

遞歸的核心就是將表達式分部分,重複的部分和截至的部分

遞歸求fib序列: 1 1 2 3 5 8

fib(n) = {

n = fib(n-2) + fib(n-1) if n>2

n = 1 else (n=1 or n=2)

}

"""

def d_func(num):

if num > 2:

return d_func(num – 2) + d_func(num – 1)

else:

return 1

print(d_func(6))

"""

lambda關鍵字表示這是一個匿名函數,通過小括弧來執行()

"""

# 無參數無返回值

def f_func():

print("Hello World 1")

f_func()

a_lambda = lambda: {

print("Hello World 2")

}

a_lambda()

(lambda: {print("Hello World 3")})()

# 無參數有返回值, lambda冒號後面不用寫return

def e_func():

return "Hello World 4"

print(e_func())

print((lambda: "Hello World 5")())

# 有參數,無返回值,參數寫在lambda後面,冒號前面

def f_func(name):

print(("Hello World 6 –> %s" % name))

f_func("張三")

(lambda name: {print(("Hello World 7 –> %s" % name))})("張三")

# 有參數,有返回值

def g_func(name):

return "Hello World 8 –> %s" % name

print(g_func("李四"))

print((lambda name: {"Hello World 9 –> %s" % name})("李四"))

"""

匿名函數lambda作為函數參數

函數內a,b進行特定操作後,最後交給callback進行回掉

"""

def h_func(a, b, callback):

print("result = %d" % callback(a, b))

# lambda a,b: a + b

h_func(3, 5, lambda a, b: a + b)

Python類教程(面向對象)

如果說函數是一個集裝箱,那麼類就是一個放集裝箱的大倉庫。我們把作一類事情的函數都會放到一個類裡面。這樣我們的程式碼就會更加美觀,更加方便看懂。

class Person(object):

def __init__(self, name, age, num):

self.name = name

self.age = age

self.num = num

def __str__(self):

return "姓名:%s 年齡: %s 學號: %s" % (self.name, self.age, self.num)

def __del__(self):

# 監聽對象銷毀,可以用來用戶復活

print("再見")

def print_info(self):

print("姓名:%s 年齡: %s 學號: %s" % (self.name, self.age,self.num))

p1 = Person("張三", 18, 1605477)

print(p1)

p2 = p1 # 引用計數+1

p3 = p1 # 引用計數+1

del p1 # 引用計數-1

del p2 # 引用計數-1

del p3 # 引用計數=0

# input()

"""

1- 使用同一個類創建的不同對象,**屬性**是需要單獨開闢記憶體的,防止一損俱損

2- 但是類的自定義方法是唯一的只有一份記憶體, 是通過self判斷不同的調用對象是誰

"""

p4 = Person("張三", 18, 1605477)

p5 = Person("張三", 18, 1605477)

print(id(p4.name)) # name作為類屬性,有單獨的記憶體空間,id地址不同

print(id(p5.name)) # 但是因為小整數型原因,顯示的id相同,但原理id是不同的

print(id(p4.print_info())) # 類方法是唯一一份的,所以id相同

print(id(p5.print_info()))

"""

單繼承,class B(A) 括弧裡面的是相對B來說的B的父類,集成了A的屬性和方法

1- python中類的屬性是直接寫在init方法中的

"""

class A(object):

def __init__(self):

self.num = 10

def print_num(self):

print(self.num + 10)

class B(A):

def my_func(self):

print("我自己B類的自定義方法")

b = B()

print(b.num)

b.print_num()

b.my_func()

"""

多繼承class D(C, A),如果多個父類C,A中都含有相同的方法和屬性print_num那麼子類D繼承的是就是C的,注意繼承的先後順序

1- 父類中的屬性和方法如果相同的話,會繼承第一個父類的屬性和方法,按照集成的順序走init構造方法

2- D類中重寫父類的方法,如果自己d類中重寫了init方法,那麼就不會繼承任何的父類屬性從init方法中

3- 換句話,子類重寫了父類的方法,那麼不在使用父類同名的方法,包括init構造方法

4- 子類中重寫了父類的方法但是還是想調用父類的方法,

"""

class C(object):

def __init__(self):

self.num = 28

def print_num(self):

print(self.num + 10)

class D(C, A):

def __init__(self):

self.age = "這是D類自己的屬性age"

self.num = "這是D類重寫父類的屬性num"

def print_num(self):

self.__init__() # 再將self.num更改回來

print("這是D自己重寫父類的方法")

# 但是子類還是想使用**父類的屬性**調用父類重名的print_num方法

# 使用A.__init__(self)方法來更改self.num的值

def print_a_num(self):

print(d.num) # 本來D對象中self.num = "這是D類重寫父類的屬性num"

A.__init__(self) # 把self傳進去,當前的self.num = 10

A.print_num(self)

# 或者使用super在子類方法中調用父類的方法

def print_c_num(self):

# super(D, self).print_num() 或者下面的簡寫形式

super().print_num()

def my_func(self):

print("我自己D類的自定義方法")

d = D()

d.print_a_num()

print(d.num)

d.print_num()

"""

類中的私有屬性和方法

1- 父類中的money不想讓子類繼承,進行私有self.__屬性名

2- 方法前加上兩個下劃線使方法私有化, 私有的屬性和方法只能在類內使用

3- # 私有屬性子類不能使用,相當於java中的對象不能加點來獲取private的屬性值

"""

class Master(object):

def __init__(self):

self.kongfu = "古法"

self.__money = 100000 # 兩個下劃線開頭表示私有屬性

def make_cake(self):

print(self.__money) # 私有屬性可以在類自己種使用

print("製作古法煎餅果子")

def __hello_python(self):

print("你好python")

lishifu = Master()

lishifu.make_cake()

print(lishifu.kongfu)

# print(lishifu.money)

"""

子類不能繼承父類的私有屬性和方法

因為根本沒有繼承下來,所以子類內部方法中根本就不能調用父類的私有屬性和方法

"""

class Prentice(Master):

def xx(self):

print("xx")

self.__hello_python()

damao = Prentice()

print(damao.kongfu)

damao.__hello_python

damao.xx()