二 程序設計與數據結構
1 萬物皆對象、Python不例外
1.1 面向對象編程基本概念:
- Python從設計之初就已經是一門面向對象的語言,比如Java, C#, Javascript,C++都是典型的面嚮對象語言.C語言和彙編語言是典型的面向過程語言.
- 面向過程的語言更傾向於功能的實現與封裝,體現計算機實現功能
- 面向對象的語言更傾向於業務層面的流程實現,體現解決具體事物流程
- 現代計算機程序都是面向過程和麪向對象的結合使用,面向對象同樣也支持面向過程
1.1.1 面向對象技術簡介
類(Class)
: 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。類變量
:類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作爲實例變量使用。數據成員
:類變量或者實例變量用於處理類及其實例對象的相關的數據。方法重寫
:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱爲方法的重寫。實例變量
:定義在方法中的變量,只作用於當前實例的類。繼承
:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作爲一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關係(例圖,Dog是一個Animal)。實例化
:創建一個類的實例,類的具體對象。方法
:類中定義的函數。對象
:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。
1.2 類和對象:
1.2.1 類定義:
class ClassName:
<statement-1>
.
.
<statement-N>
1.2.2 類的使用–實例化類的對象:
#!/usr/bin/python3
# 類的定義
class MyClass:
i = 12345
def f(self):
return 'hello world'
# 實例化類
x = MyClass()
# 訪問類的屬性和方法
print("MyClass 類的屬性 i 爲:", x.i)
print("MyClass 類的方法 f 輸出爲:", x.f())
# 結果:
# MyClass 類的屬性 i 爲: 12345
# MyClass 類的方法 f 輸出爲: hello world
1.3 類的組成–實例屬性和方法:
- 類由三個部分組成
- 實例屬性或者叫對象屬性 或簡稱屬性
- 方法–可理解爲在面向過程中定義的函數, 但是首個參數必須是‘self’
- 類屬性–沒有前兩個那麼常用和重要
- 代碼示例:
# 實例屬性 必須通過初始化或者實例化對象,通過對象去訪問,
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
print(s.name )
# 類屬性 不需要實例化對象,直接通過類名訪問
class Student(object):
name = 'Student'
print(Student.name)
# 面向對象
# 屬性和方法
class Student(object):
# 初始化方法 self指向創建的實例本身
def __init__(self,name,score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name,self.score))
# 實例化對象1
xiaohong = Student('xiaohong',98)
print(id(xiaohong))
# 實例化對象2
xiaobai = Student('xiaobai',81)
print(id(xiaobai))
# 實例化對象3
xiaobai = Student('xiaobai',81)
print(id(xiaobai))
1.4 構造方法–對象方法中的特殊方法:
- 很多類都傾向於將對象創建爲有初始狀態的。因此類可能會定義一個名爲 init() 的特殊方法(構造方法),像下面這樣:
def __init__(self):
self.data = []
- 類定義了 init() 方法的話,類的實例化操作會自動調用 init() 方法。所以在下例中,可以這樣創建一個新的實例:
x = MyClass()
- 當然, init() 方法可以有參數,參數通過 init() 傳遞到類的實例化操作上。例如:
#!/usr/bin/python3
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i) # 輸出結果:3.0 -4.5
1.4.1 self關鍵字–代表類的實例,而非類
- 方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
- 以上實例執行結果爲:
<__main__.Test instance at 0x100771878>
__main__.Test
- 從執行結果可以很明顯的看出,self 代表的是類的實例,代表當前對象的地址,而 self.class 則指向類。
- self 不是 python 關鍵字,我們可以換成其他變量名
1.5 總結
1.5.1 面向對象編程概括
- 面向對象編程是一種程序設計思想
- 面向對象把類和對象作爲程序的基本單元
- 對象包含屬性和方法
- 面向過程編程爲:函數的調用集合
- 面向對象編程爲:對象之間傳遞信息的集合
- 處處皆對象
1.5.2 類和實例總結
-
類可以理解爲圖紙或者模版
-
實例是根據類的圖紙或者模版創建出來的一個一個對象
-
類定義class,關鍵字self
-
類的初始化函數__init__
-
面向對象三大特點:繼承,封裝,多態
-
屬性和方法
1.6 訪問限制
- 通過”__”兩個下劃線可以修飾私有變量
- 通過編寫get和set方法來修改對象的屬性
- Python中沒有真正的私有屬性和私有方法
class Student(object):
# 方法 self指向創建的實例本身
def __init__(self,name,score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name,self.__score))
def get_grade(self):
if self.__score >= 90:
return 'A'
elif self.__score >= 60:
return 'B'
else:
return 'C'
def set_score(self,score):
if 0<=score<=100:
self.__score=score
else:
raise ValueError('分數請大於0小於等於100')
def get_score(self):
return self.__score
xiaolv = Student('xiaolv',45)
print(xiaolv.set_score(98))
print(xiaolv.get_score())
# python沒有真正的是私有,把私有改名稱_Student__name
print(xiaolv._Student__name)
2 面向對象—繼承和多態
2.1 繼承
- 定義一個class的時候,可以從某個現有的class繼承,新的 class稱爲子類(Subclass)
- 被繼承的class稱爲基類、父類或超類(Base class、Super class)
class Animal(object):
def run(self):
print('Animal is running')
class Dog(Animal):
pass
class Cat(Animal):
pass
dog = Dog()
# dog.run()
cat = Cat()
# cat.run()
2.1.1 多繼承【擴展】
-
Python同樣有限的支持多繼承形式。
-
需要注意圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 即方法在子類中未找到時,從左到右查找父類中是否包含方法。
#類定義
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))
#另一個類,多重繼承之前的準備
class Speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一個演說家,我演講的主題是 %s"%(self.name,self.topic))
#多重繼承
class Sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test = Sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默認調用的是在括號中排前地父類的方法
# 執行以上程序輸出結果爲:
# 我叫 Tim,我是一個演說家,我演講的主題是 Python
2.2.2 方法重寫
- 如果你的父類方法的功能不能滿足你的需求,你可以在子類重寫你父類的方法
class Animal(object):
def run(self):
print('Animal is running')
class Dog(Animal):
def run(self): # 重寫
# 調用父類的run方法
# super().run()
print('Dog is running')
def eat(self):
print('eat meat')
dog = Dog()
dog.run()
class Cat(Animal):
def run(self): # 重寫
# 調用父類的run方法
# super().run()
print('Cat is running')
def eat(self):
print('eat fish')
2.3 多態
- 代碼運行時才確定對象的具體類型
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vnmo5Q24-1573464810584)(image/.png)]
b=Animal() # b是Animal類型
c=Dog() # c是Dog類型
print(isinstance(b, Animal))
print(isinstance(c, Dog))
print(isinstance(c, Animal))
print(isinstance(b, Dog))
# 調用run_twice方法,需要傳遞Animal類的對象或者Animal的子類
def run_twice(animal):
animal.run()
animal.run()
run_twice(Dog())
run_twice(Cat())
run_twice(Animal())
2.4 類型判斷
- type()
- isinstance()
- dir() #獲得一個對象的所有屬性和方法
import types
def fn():
pass
print(type(fn)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
# getattr(),setattr(),hasattr()
class MyObject(object):
def __init__(self):
self.x = 9
def power(self):
return self.x * self.x
obj = MyObject()
# obj 有屬性'x'嗎?
print(hasattr(obj, 'x'))
print(obj.x)
# 設置一個屬性'y'
setattr(obj, 'y', 19)
print(hasattr(obj, 'y'))
print(getattr(obj, 'y'))
# dir()
print(obj.__dir__())
print(dir(obj))
a = [1,2]
print(len(a))
print(a.__len__())
2.5 封裝
- 通過類的實例直接訪問修改對象屬性,在實際的開發過程中會造成代碼的安全性和健壯性受到影響
- 通過把對象屬性私有化, 不直接提供對外部的直接訪問. 如果外部需要修改或者獲取屬性值,可以通過建立set和get方法來間接修改屬性,叫屬性的封裝.
- 例子:參看4.5.1
3 設計模式
3.1 列表生成式
- Python內置的非常簡單卻強大的可以用來創建list的生成式
- 快速的把字典內容轉變成list
d = {'x': 'A', 'y': 'B', 'z': 'C' }
print([k + '=' + v for k, v in d.items()])
# 生成list,[1,2,3...10]
print(list(range(1, 11)))
# 生成[1*1,2*2,3*3...]
print([x*x for x in range(1, 11)])
# 'abc','123' 輸出a1,a2,a3,b1,b2,b3
print([m + n for m in 'abc' for n in '123'])
print([m + n for m in 'a.b.c' for n in '123' if m != '.'])
3.2 生成器
- 循環的過程中不斷推算出後續的元素呢?這樣就不必創建完整 的list,這種一邊循環一邊計算的機制,稱爲生成器: generator
- 兩種定義
- 列表生成式
- 帶yield的generator function
g = (x * x for x in range(10))
print(g)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
for n in g:
print(n)
# yield
# 斐波那契數列 1,1,2,3,5,8
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
fib(6)
# 輸出關鍵字換成yield
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
g = fib(6)
print(next(g))
print(next(g))
print(next(g))
for n in g:
print(n)
3.2.1 Python中yield關鍵字的使用
yield
是一個類似return
的關鍵字,只是這個函數返回的是個生成器- 當你調用這個函數的時候,函數內部的代碼並不立馬執行 ,這個函數只是返回一個生成器對象
- 當你使用for進行迭代的時候,函數中的代碼纔會執行
生成器
特點:可迭代;只能讀取一次;實時生成數據,不全存在內存中。
3.3 迭代器
- for循環可以應用下列類型:
- 集合數據類型,list,tuple,dict,set,str等
- generator ,生成器和帶yield的generator function等
- 直接可作用於for循環的叫可迭代對象:Iterable
- 直接可作用於next方法的叫可以生成器對象:Iterator
- 生成器可以同時作用於for循環和next()函數,不斷調用, 直到拋出StopIteration錯誤
# 判斷一個對象是否可迭代 Iterable
from collections import Iterable
# print(isinstance([],Iterable))
# print(isinstance({},Iterable))
# print(isinstance('abc',Iterable))
# print(isinstance(123,Iterable))
# 判斷一個對象是否是生成器 Iterator
from collections.abc import Iterator
# print(isinstance([],Iterator))
# print(isinstance({},Iterator))
# print(isinstance('abc',Iterator))
# print(isinstance(123,Iterator))
print(isinstance(iter([]),Iterator))
print(isinstance(iter({}),Iterator))
print(isinstance(iter('abc'),Iterator))
4 函數的高級應用
4.1 函數即變量
- 變量可以指向函數
- 函數名也是變量
- 函數可以作爲參數傳入到方法內部
- 函數本身也可以賦值給變量,即:變量可以指向函數
# abs(-10)函數調用,abs是函數本身
print(abs(-10))
f = abs
print(f)
print(f(-10))
4.2 Python內置的map函數
- map()函數接收兩個參數,一個是函數,一個是Iterable
- map將傳入的函數依次作用到序列的每個元素,並把結果作爲 新的Iterator返回
l = [1,2,3,4,5,6,7,8,9]
def f(x):
return x*x
m = map(f,l)
print(m)
# print(list(m))
# for n in m:
# print(n)
print(next(m))
print(next(m))
print(next(m))
# l 列表中每個int轉換成字符串
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(map(str,l)))
4.3 Python內置的reduce函數
- reduce把一個函數作用在一個序列[x1, x2, x3, …]上 ,reduce 把結果繼續和序列的下一個元素做累積計算
- reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
l = [4,2,5,7,8,9] #獲得425789
from functools import reduce
def f(x, y):
return x * 10 + y
print(reduce(f,l))
print(type(reduce(f,l)))
4.4 練習
# str()——》int()
'5632'——》5632
# 思路
# 1. 字符串每個元素取出來,轉化成對應的數字,得到一個數字序列
# 2. 通過數字序列每兩個*10 相加,得到一個整數
def f(x,y):
return x * 10 + y
def char2num(s):
digits = {'0': 0, '1': 1, '2' :2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
return digits[s]
s1 = '5632'
nums = reduce(f,map(char2num, s1))
print(type(nums))
print(nums)
4.5 裝飾器
- python裝飾器就是用於拓展原來函數功能的一種函數,這個函數的特殊之處在於它的返回值也是一個函數,
- 使用python裝飾器的好處就是在
不用更改原函數的代碼前提下給函數增加新的功能
。
import datetime
# 裝飾器 以一個函數作爲參數,並返回一個函數
def log(f):
def write_log(*args, **kw):
with open('./a.txt', 'w') as f1:
f1.write(f.__name__)
print('寫入日誌成功,函數名字是:%s'%f.__name__)
return f(*args, **kw)
return write_log
@log
def now():
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
4.5.1 Python內置的裝飾器 @property @setter實現對象屬性的封裝
- @property 使調用類中的方法像引用類中的字段屬性一樣。
- @property 負責裝飾一個對象函數,讓其生成對應的setter和getter函數,調用的時候,直接可以使用對象名.函數名這種類似於屬性的調用方式來執行函數
class Student(object):
def __init__(self, score):
self.__score = score
def get_score(self):
return self.__score
def set_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
stu1 = Student(90)
print(stu1.set_score(85))
print(stu1.get_score())
# 加上裝飾器,方法變屬性
class Student(object):
def __init__(self, score):
self.__score = score
@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
stu2 = Student('67')
stu2.score = 59
print(stu2.score)
4.5.2 靜態方法與類方法
- @staticmethod 將類中的方法裝飾爲靜態方法,即類不需要創建實例的情況下,可以通過類名直接引用。到達將函數功能與實例解綁的效果。
class TestClass:
name = "test"
def __init__(self, name):
self.name = name
@staticmethod
def fun(self, x, y):
return x + y
cls = TestClass("felix")
print ("通過實例引用方法")
print (cls.fun(None, 2, 3)) # 參數個數必須與定義中的個數保持一致,否則報錯
print ("類名直接引用靜態方法")
print (TestClass.fun(None, 2, 3))# 參數個數必須與定義中的個數保持一致,否則報錯
- @classmethod 類方法的第一個參數是一個類,是將類本身作爲操作的方法。類方法被哪個類調用,就傳入哪個類作爲第一個參數進行操作。
class Car(object):
car = "audi"
@classmethod
def value(self, category): # 可定義多個參數,但第一個參數爲類本身
print ("%s car of %s" % (category, self.car))
class BMW(Car):
car = "BMW"
class Benz(Car):
car = "Benz"
print ("通過實例調用")
baoma = BMW()
baoma.value("Normal") # 由於第一個參數爲類本身,調用時傳入的參數對應的時category
print ("通過類名直接調用")
Benz.value("SUV")
5 異常處理
5.1 異常介紹:
- 即便Python程序的語法是正確的,在運行它的時候,也有可能發生錯誤。運行期檢測到的錯誤被稱爲異常。
- 大多數的異常都不會被程序處理,都以錯誤信息的形式展現在這裏:
- 異常以不同的類型出現,這些類型都作爲信息的一部分打印出來: 例子中的類型有 ZeroDivisionError,NameError 和 TypeError
>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly
- Python的一些內建異常:
Exception 常規錯誤的基類
AttributeError 對象沒有這個屬性
IOError 輸入/輸出操作失敗
IndexError 序列中沒有此索引(index)
KeyError 映射中沒有這個鍵
NameError 未聲明/初始化對象 (沒有屬性)
SyntaxError Python 語法錯誤
TypeError 對類型無效的操作
ValueError 傳入無效的參數
ZeroDivisionError 除(或取模)零 (所有數據類型)
5.2 使用異常可以讓你的程序繼續執行:
- 沒有異常處理的:特點是出現異常會終止程序執行
print("start.....")
x = int(input("Please enter a number: "))
print("number:",x)
print("ok....")
print("end.....")
- 使用了有異常處理的代碼,程序會執行到最後
print("start.....")
try:
x = int(input("Please enter a number: "))
print("number:",x)
print("ok....")
except ValueError:
print("Oops! That was no valid number. Try again")
print("end.....")
- try語句按照如下方式工作;
- 首先,執行try子句(在關鍵字try和關鍵字except之間的語句)
- 如果沒有異常發生,忽略except子句,try子句執行後結束。
- 如果在執行try子句的過程中發生了異常,那麼try子句餘下的部分將被忽略。如果異常的類型和 except 之後的名稱相符,那麼對應的except子句將被執行。最後執行 try 語句之後的代碼。
- 如果一個異常沒有與任何的except匹配,那麼這個異常將會傳遞給上層的try中。
- 一個 try 語句可能包含多個except子句,分別來處理不同的特定的異常。最多隻有一個分支會被執行。
- 處理程序將只針對對應的try子句中的異常進行處理,而不是其他的 try 的處理程序中的異常。
- 一個except子句可以同時處理多個異常,這些異常將被放在一個括號裏成爲一個元組,例如:
except (RuntimeError, TypeError, NameError):
pass
- 最後一個except子句可以忽略異常的名稱,它將被當作通配符使用。你可以使用這種方法打印一個錯誤信息,然後再次把異常拋出。
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
5.3:使用異常可以定位問題原因
- 一個 try 語句可能包含多個except子句,分別來處理不同的特定的異常。最多隻有一個分支會被執行
- 最後一個except子句可以忽略異常的名稱,它將被當作通配符使用
print("start.....")
try:
x = int(input("Please enter a number: "))
print("number:",x)
print(100/x)
print("ok....")
except ValueError:
print("非純數字錯誤!")
except ZeroDivisionError:
print("不可以爲零錯誤!")
except:
print("可選的未知錯誤!")
print("end.....")
- 一個except子句可以同時處理多個異常,這些異常將被放在一個括號裏成爲一個元組
print("start.....")
try:
x = int(input("Please enter a number: "))
print("number:",x)
print(100/x)
print("ok....")
except (ValueError,ZeroDivisionError):
print("非純數字或不可以爲零錯誤!")
except:
print("可選的未知錯誤!")
raise #重新拋出這個異常
print("end.....")
5.4 拋出異常(發現問題讓其他函數解決):
- Python 使用 raise 語句拋出一個指定的異常。例如:
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: HiThere
- raise 唯一的一個參數指定了要被拋出的異常。它必須是一個異常的實例或者是異常的類(也就是 Exception 的子類)。
- 如果你只想知道這是否拋出了一個異常,並不想去處理它,那麼一個簡單的 raise 語句就可以再次把它拋出。
>>> try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
NameError: HiThere
5.5 使用異常可以定位到代碼執行中出現問題的函數
- 代碼順序執行,函數之間互相調用,如果發生錯誤。我們並不知道那裏發生了錯誤,需要測試一下我們的代碼。
def foo(s):
return 100/int(s)
def bar(s):
return foo(s)*2
# 在python中,如果py是單獨運行,__name__=='__main__', \
# 如果py文件被其他模塊引入調用的時候就不等於 import
if __name__ == '__main__':
'''
測試 給我們自己調用
'''
try:
bar('0')
except Exception as e:
print('Error:',e)
finally:
print('finally...')
6 第三方模塊的安裝與調用
6.1 自定義Python模塊
- 在導入一個包的時候,Python 會根據 sys.path 中的目錄來尋找這個包中包含的子目錄。
- 目錄只有包含一個叫做
__init__.py
的文件纔會被認作是一個包,主要是爲了避免一些濫俗的名字(比如叫做string
)不小心的影響搜索路徑中的有效模塊。 - 最簡單的情況,放一個空的 :
file:__init__.py
就可以了。當然這個文件中也可以包含一些初始化代碼或者爲(將在後面介紹的)__all__
變量賦值。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EPJPxMYH-1573464810589)(image/.png)]
6.2 模塊的使用
- 一個.Py文件稱之爲一個模塊(Module)
- 好處:
- 便於代碼維護,把很多函數放到不同文件,一個.py文件 的 代碼數量少
- 一個模塊可以被其他地方引用,代碼不必從零寫起
- 使用模塊還可以避免函數名和變量名衝突。相同名字的函數和變量完全可以分別存在不同的模塊中
6.2.1 模塊的導入與使用
import 語句:
- 想使用 Python 源文件,只需在另一個源文件裏執行 import 語句
import time
# 格式化成2016-03-20 11:45:39形式
print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
from…import 語句:
- Python的from語句讓你從模塊中導入一個指定的部分到當前命名空間中
from time import strftime,localtime
# 格式化成2016-03-20 11:45:39形式
print (strftime("%Y-%m-%d %H:%M:%S", localtime()))
模塊的使用
- 模塊分內置模塊和第三方模塊
- 好處Python解釋器把一個特殊變量__name__置爲__main__, 而如果在其他地方導入該hello模塊時,if判斷將失敗
- 使用import hello
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FH2yJvOt-1573464810591)(image/.png)]
6.3 第三方模塊的安裝
用pip命令安裝
- pip install 模塊名
- pip uninstall 模塊名
- pip freeze --查看都安裝了哪些模塊名
whl下載安裝的方式
-
網址: https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下載
-
安裝:pip install 文件包名
-
pip 命令的詳細使用方法請參照附錄9 附錄:pip命令
-
-
使用Python的另一個發行版本,anaconda
-
Pycharm 裏面安裝
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5XacUGWW-1573464810592)(image/.png)]
7 字符編碼
7.1 字符編碼類型
- ASCII編碼
- 中文GB2312
- Unicode
- UTF8
print(ord('A'))
print(ord('我'))
print(chr(65))
print(chr(25105))
# 傳輸和保存 需要對字符進行 編解碼,utf-8通用編解碼
x = b'ABC' # 字節數組,byte數組
print(x)
# 中文編碼範圍超過了ASC編碼範圍,報錯
# x = b'你好' # 字節數組,byte數組
# print(x)
# 在bytes中,無法顯示ASC字符的字節,用\x##來顯示
print('你好'.encode('gbk'))
print('ABC'.encode('utf-8'))
print(b'\xc4\xe3\xba\xc3'.decode('gbk'))
# 中文佔用多少字節
print(len('你好AB'))
print(len('你好'.encode('utf-8')))
print(len('你好'.encode('gbk')))
7.2 字符串編碼轉化
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cHETpCcj-1573464810593)(image/.png)]
8 案例實戰:圖片和視頻轉字符動畫
- 需求:
- 1.把一張圖片,轉化爲字符畫
- 2.把一個視頻,轉化成字符動畫
- 原理:
- 字符畫是一系列字符的組合,我們可以把字符看作是比較大塊的像 素,一個字符能表現一種顏色(爲了簡化可以這麼理解),字符的種 類越多,可以表現的顏色也越多,圖片也會更有層次感
8.1 名詞介紹
三原色
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2yrJ6mgD-1573464810594)(image/.png)]
顏色碼對照表
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nstnJGD6-1573464810595)(image/.png)]
灰度圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0rM3PCRG-1573464810597)(image/.png)]
點陣字
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xqwEiJVj-1573464810598)(image/.png)]
分辨率
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Psgzxe8l-1573464810599)(image/.png)]
灰度圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ajrpbVFF-1573464810600)(image/.png)]
彩色圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-deRnnlQE-1573464810601)(image/.png)]
8.2 原理步驟
- 首先使用 PIL 的 Image.open 打開圖片文件,獲得對象 im
- 使用 PIL 庫的 im.resize() 調整圖片大小對應到輸出的字符畫的寬 度和高度,注意這個函數第二個參數使用 Image.NEAREST,表示輸出低質量的圖片。
- 遍歷提取圖片中每行的像素的 RGB 值,調用 getchar 轉成對應的字符
- 將所有的像素對應的字符拼接在一起成爲一個字符串 txt
- 打印輸出字符串 txt
- 如果執行時配置了輸出文件,將打開文件將 txt 輸出到文件,如果 沒有,則默認輸出到 output.txt 文件
8.3 第三方模塊的引用
- pip3 install pillow
- pip3 install pyprind
- pip3 install numpy
- pip3 install opencv-python
8.4 視頻轉動畫實現設計思路
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vNHP2H2a-1573464810602)(image/.png)]
9 圖形用戶界面實戰【擴展】
9.1 圖形用戶界面(GUI)
- 本節介紹如何創建Python程序的圖形用戶界面(GUI),也就是那些帶有按鈕和文本框的窗口。
- 目前支持Python的所謂"GUI工具包"有很多,但沒有一個被認爲是標準的,也好,選擇空間大
- GUI工具包:
工具包名 | 介紹 | URL地址 |
---|---|---|
Tkinter | 使用Tk平臺。很容易得到。半標準 | http://wiki.python.org/moin/TkInter |
wxpython | 基於wxWindows。跨平臺越來越流行 | http://wxpython.org |
PythonWin | 只能在Windows上使用。 | http://starship.python.net/crew/mhammond |
Java Swing | 只能用於Python。使用本機的Java GUI | http://java.sun.com/docs/books/tutorial/uiswing |
PyGTK | 使用GTK平臺,在Linux上很流行 | http://pygtk.org |
PyQt | 使用Qt平臺,跨平臺 | http://wiki.python.org/moin/PyQt |
9.2 安裝:wxpython
pip install -U wxpython
--Installing collected packages: six, wxpython
--Successfully installed six-1.11.0 wxpython-4.0.1
- 開發步驟:
1. 導入wx模塊
2. 定義一個應用程序對象
3. 創建wx.Frame主窗口對象,設置窗口標題和大小
4. 創建組件、佈局、添加事件處理等操作
5. 通過Frame的show()方法顯示窗體
6. 進入應用程序事件主循環
9.3 創建並且顯示一個框架
# 導入wxPython模塊
import wx
# 創建應用程序對象
app = wx.App()
win = wx.Frame(None) #創建一個單獨的窗口
btn=wx.Button(win) #創建一個按鈕組件
win.Show() #設置可見
#進入應用程序事件主循環
app.MainLoop()
9.4 設置標題,添加按鈕
import wx
app = wx.App()
win = wx.Frame(None,title="我的記事本") #創建一個單獨的窗口
loadButton = wx.Button(win,label="Open")
saveButton = wx.Button(win,label="Save")
win.Show()
app.MainLoop() #進入應用程序事件主循環
9.5 設置標題,添加按鈕,並簡單佈局
import wx
app = wx.App()
win = wx.Frame(None,title="我的記事本",size=(410,335)) #創建一個單獨的窗口
loadButton = wx.Button(win,label="Open",pos=(225,5),size=(80,25))
saveButton = wx.Button(win,label="Save",pos=(315,5),size=(80,25))
filename = wx.TextCtrl(win,pos=(5,5),size=(210,25))
contents = wx.TextCtrl(win,pos=(5,35),size=(390,260),style=wx.TE_MULTILINE | wx.HSCROLL)
win.Show()
app.MainLoop() #進入應用程序事件主循環
9.6 組件佈局
import wx
app = wx.App()
win = wx.Frame(None,title="我的記事本",size=(410,335)) #創建一個單獨的窗口
bkg = wx.Panel(win)
#創建組件
loadButton = wx.Button(bkg,label="Open")
saveButton = wx.Button(bkg,label="Save")
filename = wx.TextCtrl(bkg)
contents = wx.TextCtrl(bkg,style=wx.TE_MULTILINE | wx.HSCROLL)
#佈局容器
hbox=wx.BoxSizer() #默認水平佈局
hbox.Add(filename,proportion=1,flag=wx.EXPAND)
hbox.Add(loadButton,proportion=0,flag=wx.LEFT,border=5)
hbox.Add(saveButton,proportion=0,flag=wx.LEFT,border=5)
#佈局容器
vbox=wx.BoxSizer(wx.VERTICAL) #垂直佈局
vbox.Add(hbox,proportion=0,flag=wx.EXPAND|wx.ALL,border=5)
vbox.Add(contents,proportion=1,flag=wx.EXPAND|wx.LEFT|wx.BOTTOM|wx.RIGHT,border=50)
bkg.SetSizer(vbox)
win.Show()
app.MainLoop() #進入應用程序事件主循環
9.7 爲按鈕添加事件並完成其事件處理操作
import wx
#按鈕事件處理函數
def load(event):
'''加載文件內容'''
file=open(filename.GetValue(),"r")
contents.SetValue(file.read())
file.close()
def save(event):
'''保持文件內容'''
file=open(filename.GetValue(),"w")
file.write(contents.GetValue())
file.close()
#
app = wx.App()
win = wx.Frame(None,title="我的記事本",size=(410,335)) #創建一個單獨的窗口
win.Show()
loadButton = wx.Button(win,label="Open",pos=(225,5),size=(80,25))
saveButton = wx.Button(win,label="Save",pos=(315,5),size=(80,25))
loadButton.Bind(wx.EVT_BUTTON,load)
saveButton.Bind(wx.EVT_BUTTON,save)
filename = wx.TextCtrl(win,pos=(5,5),size=(210,25))
contents = wx.TextCtrl(win,pos=(5,35),size=(390,260),style=wx.TE_MULTILINE | wx.HSCROLL)
app.MainLoop() #進入應用程序事件主循環
10 飛機大戰【擴展】
- 本次開發需要安裝一個Python的遊戲模塊:pygame。 方式:
pip install pygame
- 開發步驟如下:
- 創建遊戲主頁面窗口,並添加滾動背景。
- 添加鍵盤事件處理函數
- 放置玩家英雄飛機,並綁定鍵盤事件,實現飛機移動
- 添加玩家子彈,並實現發射
- 隨機顯示敵機
- 實現敵機與子彈的碰撞檢測
import pygame
from pygame.locals import * #pygame使用的各種常量
import time,random
# 實現敵機與子彈的碰撞檢測。
class HeroPlane:
''' 玩家飛機類(英雄) '''
def __init__(self, screen_temp):
self.x = 200
self.y = 400
self.screen = screen_temp
self.image = pygame.image.load("./images/me.png")
self.bullet_list = [] #存儲發射出去的子彈對象引用
def display(self):
''' 繪製玩家到窗口中 '''
#遍歷移動子彈
for bullet in self.bullet_list:
bullet.display()
#移動子彈,並判斷是否越界。
if bullet.move():
self.bullet_list.remove(bullet)
self.screen.blit(self.image, (self.x, self.y))
def move_left(self):
''' 左移動,並判斷防止越界 '''
self.x -= 5
if self.x<0:
self.x=0
def move_right(self):
''' 右移動,並判斷防止越界 '''
self.x += 5
if self.x > 406:
self.x = 406
def fire(self):
self.bullet_list.append(Bullet(self.screen, self.x, self.y))
print(len(self.bullet_list))
class Bullet:
''' 玩家子彈類 '''
def __init__(self, screen_temp, x, y):
self.x = x+51
self.y = y
self.screen = screen_temp
self.image = pygame.image.load("./images/pd.png")
def display(self):
self.screen.blit(self.image, (self.x, self.y))
def move(self):
self.y-=10
if self.y<-20:
return True
class EnemyPlane:
"""敵機的類"""
def __init__(self, screen_temp):
self.x = random.choice(range(408))
self.y = -75
self.screen = screen_temp
self.image = pygame.image.load("./images/e"+str(random.choice(range(3)))+".png")
def display(self):
self.screen.blit(self.image, (self.x, self.y))
def move(self,hero):
self.y += 4
#遍歷玩家的子彈,並做碰撞檢測
for bo in hero.bullet_list:
if bo.x>self.x+12 and bo.x<self.x+92 and bo.y>self.y+20 and bo.y<self.y+60:
hero.bullet_list.remove(bo)
return True
#判斷敵機是否越界
if self.y>512:
return True;
def key_control(hero_temp):
''' 鍵盤控制函數 '''
#獲取事件,比如按鍵等
for event in pygame.event.get():
#判斷是否是點擊了退出按鈕
if event.type == QUIT:
print("exit")
exit()
#獲取按下的鍵(返回的是元組值)
pressed_keys = pygame.key.get_pressed()
#檢測是否按下a或者left鍵
if pressed_keys[K_LEFT] or pressed_keys[K_a]:
print('left')
hero_temp.move_left()
#檢測是否按下d或者right鍵
elif pressed_keys[K_RIGHT] or pressed_keys[K_d]:
print('right')
hero_temp.move_right()
#檢查是否是空格鍵
if pressed_keys[K_SPACE]:
print('space')
hero_temp.fire()
def main():
'''遊戲的主程序執行函數'''
#1. 創建窗口:set_mode(分辨率=(0,0),標誌=0,深度=0)
screen = pygame.display.set_mode((512,568),0,0)
#2. 創建一個遊戲背景圖片(512*1536)
background = pygame.image.load("./images/bg2.jpg")
m=-968 #初始化遊戲背景圖片標軸y的值
#3. 創建一個玩家飛機對象
hero = HeroPlane(screen)
#4.定義用於存放敵機列表
enemylist = []
while True:
#繪製位圖
screen.blit(background,(0,m))
m+=2
if m>=-200:
m = -968
#顯示英雄玩家
hero.display()
# 鍵盤控制(負責移動玩家)
key_control(hero)
#隨機輸出敵機
if random.choice(range(50))==10:
enemylist.append(EnemyPlane(screen))
#遍歷所有敵機,顯示敵機,移動敵機,並與玩家子彈碰撞檢測
for em in enemylist:
em.display()
if em.move(hero):
enemylist.remove(em)
#更新屏幕顯示
pygame.display.update()
# 定時睡眠(時鐘)
time.sleep(0.04)
# 判斷當前是否是主程序,若是就執行主程序。
if __name__ == "__main__":
main()
11 附錄:pip命令
------------------------------------------------------------
列出已安裝的包:
$ pip list
$ pip freeze # 查看自己安裝的
安裝軟件(安裝特定版本的package,通過使用==, >=, <=, >, <來指定一個版本號)**
$ pip install SomePackage
$ pip install 'Markdown<2.0'
$ pip install 'Markdown>2.0,<2.0.3'
卸載軟件pip uninstall SomePackage
$ pip uninstall SomePackage
下載所需的軟件包:
$ pip download SomePackage -d directory
例如下載PyMySQL軟件包
$ pip download PyMySQL -d D:/pypackage
安裝下載好的軟件包文件
$ pip install 目錄/軟件包文件名
如安裝PyMySQL軟件包
$ pip3.6 install D:/pypackage/PyMySQL-0.7.11-py2.py3-none-any.whl
##12 附錄: 類的專有方法(魔術方法)
類的專有方法:
-
__init__
: 構造函數,在生成對象時調用 -
__del__
: 析構函數,釋放對象時使用 -
__repr__
: 打印,轉換 -
__setitem__
: 按照索引賦值 -
__getitem__
: 按照索引獲取值 -
__len__
: 獲得長度 -
__cmp__
: 比較運算 -
__call__
: 函數調用 -
__add__
: 加運算 -
__sub__
: 減運算 -
__mul__
: 乘運算 -
__div__
: 除運算 -
__mod__
: 求餘運算 -
__pow__
: 乘方 -
Python同樣支持運算符重寫,我們可以對類的專有方法進行重寫,實例如下:
#!/usr/bin/python3
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
# 以上代碼執行結果如下所示:
# Vector(7,8)