1. 程式人生 > >python學習心得與總結三

python學習心得與總結三

本週主要學習了類和麵向物件的知識,學得容易,靈活運用卻很難,還需要多加練習孰能生巧。

函式

引數、預設值、可變引數、關鍵字引數、命名關鍵字引數

可變引數:*args
關鍵字引數:**kwargs
返回值

巢狀定義
高階函式、λ函式(匿名函式)、閉包、偏函式、柯里化

識別符號
print(a)
作用域
L–E–G–B

類和物件

程式設計七大原則

單一職責原則

開閉原則

依賴原則

里氏替換原則

介面隔離原則(x)

合成聚合複用原則

迪米特法則(最少知識原則)

#關鍵字引數--字典--根據引數名來決定如何執行
#可變引數--輸出的是元組
def
say_hello(**kwargs):
print(kwargs) for key in kwargs: print(key,'-->',kwargs[key]) if 'name' in kwargs: print('你好,%s!' %kwargs['name']) elif 'age' in kwargs: age = kwargs['age'] if age<= 16: print('你還是個小屁孩') else: print('你是個成年人'
) else: print('請提供個人資訊') def main(): say_hello(name='熊彪',age='25') param = {'name':'王大錘','age':16,'tel':'15884550995'} #如果希望將一個字典作為關鍵字引數傳入 需要在引數名前放兩個* say_hello(**param) mylist = [1,2,3,7,8] #如果希望將一個列表或元組作為可變引數傳入 需要在引數名前放一個* #命名關鍵字引數 def foo (a,b,c,*,name,age):
print(a+b+c) print(name,':',age) foo(1,2,3,name = '熊彪',age = '25') if __name__ == '__main__': main()
高階函式,比如f(f(x))
高內聚 低耦合
通過向函式中傳入函式,可以寫出更通用的程式碼
calc函式中的第二個引數是另一個函式 它代表了一個二元運算
這樣calc函式就不需要跟某一種特定的二元運算耦合在一起
所以calc函式變得通用性更強 可以由傳入的第二個引數來決定到底是做什麼運算
@property裝飾器
slots魔法

(限定物件只能繫結某些屬性)

繼承和多型

子類在繼承了父類的方法後,可以對父類已有的方法給出新的實現版本,這個動作稱之為方法重寫(override)。通過方法重寫我們可以讓父類的同一個行為在子類中擁有不同的實現版本,當我們呼叫這個經過子類重寫的方法時,不同的子類物件會表現出不同的行為,這個就是多型(poly-morphism)。

def my_sum(my_list):
    total = 0
    for val in my_list:
        total += val
    return total

def add(x,y):
    return x*y


def calc(my_list,op):
    total = my_list[0]
    for index in range(1,len(my_list)):
        total = op(total,my_list[index])
    return  total

def main():
    my_list = [1,3,5,2,7,8,9]
    print(calc(my_list,add))
    print(my_sum(my_list))


if __name__ == '__main__':
    main()


def record(fn):
    def wrapper(*args,**kwargs):
        print('準備執行%s函式' %fn.__name__)
        print(args)
        print(kwargs)
        #此行程式碼在執行被裝飾的函式
        #在這行程式碼的前後我們可以附加其他的程式碼
        #這些程式碼可以讓我們在執行函式時做一些額外的工作
        val = fn(*args,**kwargs)
        print('%s函式執行完成' %fn.__name__)
        print('返回了%d' %val)
        return  val
    return  wrapper
#通過裝飾器修飾f函式 讓f函式在執行過程中可以做更多額外的操作
@record
def f(n):
    if n==0 or n==1:
        return 1
    return n*f(n-1)

if __name__ == '__main__':
    print(f(5))
#奧特曼打小怪獸
from random import randint


class Ultraman(object):
    __slots__ = ('_name','_hp','_mp') #對物件屬性做限制,不能加別的屬性

    def __init__(self, name, hp, mp):
        self._name = name
        self._hp = hp
        self._mp = mp
#屬性的訪問器與修改器
    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp >= 0 else 0

    def attack(self, monster):
        monster.hp -= randint(15, 25)

    def huge_attack(self, monster):
        if self.mp >= 50:
            self.mp -= 50
            injury = monster.hp * 3 // 4
            injury = injury if injury >= 50 else 50
            monster.hp -= injury
        else:
            self.attack(monster)

    def magic_attack(self, monsters):
        if self._mp >= 20:
            self._mp -= 20
            for monster in monsters:
                monster.hp -= randint(10, 15)

    def __str__(self):
        return '%s奧特曼\n' % self._name + \
               '生命值:%d\n' % self._hp + \
               '魔法值:%d\n' % self._mp


class Monster(object):
    __slots__ = ('_name','_hp')

    def __init__(self, name, hp):
        self._name = name
        self._hp = hp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp >= 0 else 0

    def attack(self, ultraman):
        ultraman.hp -= randint(10, 20)

    def __str__(self):
        return '%s小怪獸\n' % self._name + \
               '生命值:%d\n' % self._hp



def main():
    u = Ultraman('熊彪', 1000, 200)
    m1 = Monster('陳晨1',250)
    m2 = Monster('陳晨2',500)
    m3 = Monster('陳晨3',800)
    ms = [m1,m2,m3]

    def die(m1,m2,m3):
        return False if m1.hp == 0 and m2.hp == 0 and m3.hp == 0 else True

    attack_round = 1
    while u.hp > 0 and die(m1,m2,m3):
        print('====第%d回合====' % attack_round)
        index = randint(0,2)
        u.attack(ms[index])
        u.magic_attack(ms)
        if ms[index].hp > 0:
            ms[index].attack(u)
        print(u)
        print(m1)
        print(m2)
        print(m3)
        # for n in range(3):
        #     print('小怪獸%s的生命值為%s' %(str(ms[n]._name),str(ms[n]._hp)))
        attack_round += 1
    if u.hp > 0:
        print('%s奧特曼勝利!' % u.name)
    else:
        print('小怪獸勝利!')


if __name__ == '__main__':
    main()
奧特曼打一群小怪獸
from random import randint, randrange
from abc import ABCMeta,abstractmethod

class Fighter(object,metaclass=ABCMeta):
    """戰鬥者"""

    # 通過__slots__魔法限定物件可以繫結的成員變數
    __slots__ = ('_name', '_hp')

    def __init__(self, name, hp):
        """
        初始化方法

        :param name: 名字
        :param hp: 生命值
        """
        self._name = name
        self._hp = hp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp >= 0 else 0

    @abstractmethod
    def attack(self,other):
        pass

    @property
    def alive(self):
        return self._hp > 0


class Ultraman(Fighter):
    """奧特曼"""

    __slots__ = ('_name', '_hp', '_mp')

    def __init__(self, name, hp, mp):
        """
        初始化方法

        :param name: 名字
        :param hp: 生命值
        :param mp: 魔法值
        """
        super().__init__(name, hp)
        self._mp = mp

    def attack(self, monster):
        """
        攻擊

        :param monster: 被攻擊的小怪獸
        """
        monster.hp -= randint(15, 25)

    def huge_attack(self, monster):
        """
        究極必殺技

        :param monster: 被攻擊的小怪獸

        :return: 使用成功返回True否則返回False
        """
        if self._mp >= 50:
            self._mp -= 50
            injury = monster.hp * 3 // 4
            injury = injury if injury >= 50 else 50
            monster.hp -= injury
            return True
        else:
            self.attack(monster)
            return False

    def magic_attack(self, monsters):
        """
        魔法攻擊

        :param monsters: 被攻擊的一群小怪獸

        :return: 使用魔法成功返回True否則返回False
        """
        if self._mp >= 20:
            self._mp -= 20
            for monster in monsters:
                if monster.alive>0:
                    monster.hp -= randint(10, 15)
            return True
        else:
            return False

    def resume(self):
        """恢復魔法值"""
        incr_point = randint(1, 10)
        self._mp += incr_point
        return incr_point

    def __str__(self):
        return '~~~%s奧特曼~~~\n' % self._name + \
               '生命值: %d\n' % self._hp + \
               '魔法值: %d\n' % self._mp


class Monster(Fighter):
    """小怪獸"""

    __slots__ = ('_name', '_hp')

    def attack(self, ultraman):
        """
        攻擊

        :param ultraman: 被攻擊的奧特曼
        """
        ultraman.hp -= randint(10, 20)

    def __str__(self):
        return '~~~%s小怪獸~~~\n' % self._name + \
               '生命值: %d\n' % self._hp


def is_any_alive(monsters):
    """判斷有沒有小怪獸是活著的"""
    for monster in monsters:
        if monster.alive > 0:
            return True
    return False


def select_alive_one(monsters):
    """選中一隻活著的小怪獸"""
    monsters_len = len(monsters)
    while True:
        index = randrange(monsters_len)
        monster = monsters[index]
        if monster.alive > 0:
            return monster


def display_info(ultraman, monsters):
    """顯示奧特曼和小怪獸的資訊"""
    print(ultraman)
    for monster in monsters:
        print(monster, end='')


def main():
    u = Ultraman('駱昊', 1000, 120)
    m1 = Monster('舒小玲', 250)
    m2 = Monster('白元芳', 500)
    m3 = Monster('王大錘', 750)
    ms = [m1, m2, m3]
    fight_round = 1
    while u.alive and is_any_alive(ms):
        print('========第%02d回合========' % fight_round)
        m = select_alive_one(ms)  # 選中一隻小怪獸
        skill = randint(1, 10)   # 通過隨機數選擇使用哪種技能
        if skill <= 6:  # 60%的概率使用普通攻擊
            print('%s使用普通攻擊打了%s.' % (u.name, m.name))
            u.attack(m)
            print('%s的魔法值恢復了%d點.' % (u.name, u.resume()))
        elif skill <= 9:  # 30%的概率使用魔法攻擊(可能因魔法值不足而失敗)
            if u.magic_attack(ms):
                print('%s使用了魔法攻擊.' % u.name)
            else:
                print('%s使用魔法失敗.' % u.name)
        else:  # 10%的概率使用究極必殺技(如果魔法值不足則使用普通攻擊)
            if u.huge_attack(m):
                print('%s使用究極必殺技虐了%s.' % (u.name, m.name))
            else:
                print('%s使用普通攻擊打了%s.' % (u.name, m.name))
                print('%s的魔法值恢復了%d點.' % (u.name, u.resume()))
        if m.alive > 0:  # 如果選中的小怪獸沒有死就回擊奧特曼
            print('%s回擊了%s.' % (m.name, u.name))
            m.attack(u)
        display_info(u, ms)  # 每個回合結束後顯示奧特曼和小怪獸的資訊
        fight_round += 1
    print('\n========戰鬥結束!========\n')
    if u.alive > 0:
        print('%s奧特曼勝利!' % u.name)
    else:
        print('小怪獸勝利!')


if __name__ == '__main__':
    main()
約瑟夫環問題
def main():
    persons = [True]*30
    counter = 0
    index = 0
    number = 0
    while counter<15:
        if persons[index]:
            number += 1
            if number == 9:
                persons[index] = False
                counter +=1
                number = 0
        index +=1
        index %= 30
    for person in persons:
        print('基督徒' if person else '非基督徒',end = '')

if __name__ == '__main__':
    main()
線段上有兩個點–has-a–關聯關係
奧特曼打小怪獸—依賴關係
學生是人–繼承關係
from  math import sqrt
class Point(object):

    def __init__(self,x=0,y=0):
        self._x = x
        self._y = y

    @property
    def x(self):
       return self._x
    @x.setter
    def x(self,x):
        self._x = x

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self,y):
        self._y=y


    def move_to(self,x,y):
        self._x = x
        self._y = y

    def move_by(self,dx,dy):
        self._x += dx
        self._y += dy

    def distance_to(self,other):
        dx = self._x-other.x
        dy = self._y-other.y
        return  sqrt(dx**2+dy**2)

    def __str__(self):
        return '(%s,%s)' %(str(self._x),str(self._y))


class Line(object):

    def __init__(self,start,end):
        self._start = start
        self._end = end


    @property
    def length(self):
        return self._start.distance_to(self._end)


def main():
    p1 = Point(3,5)
    print(p1)
    p2 = Point()
    print(p2)
    line = Line(p1,p2)
    print(line.length)

if __name__ == '__main__':
    main()

繼承-從已經有的類建立新類的過程
提供繼承資訊的稱為父類(超類/基類)
得到繼承資訊的稱為子類(派生類/衍生類)
通過繼承我們可以將子類中的重複程式碼抽取到父類中
子類通過繼承並複用這些程式碼來減少重複程式碼的編寫
將來如果要維護子類的公共程式碼只需要在父類中進行操作即可
方法重寫(override)–覆蓋/置換/覆寫
子類在繼承父類方法之後 對方法進行了重新實現
當我們給子類物件傳送watch_av訊息時執行的是子類重寫過的方法

靜態方法是指發給物件的包裝器:@staticmethod
發給類的包裝器是抽象類:@classmethod:def (物件)(cls,物件屬性)

class Teacher(object):

    def __init__(self,name,age,title):
        self._name=name
        self._age=age
        self._title=title

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @name.setter
    def name(self,name):
        self._name = name

    @age.setter
    def age(self,age):
        self._age=age

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self,title):
        self._title=title

    def teach(self,course):
        print('%s%s正在講%s.' %(self._name,self._title,course))





def main():

     t=Teacher('陳晨',25,'老師')
     t.teach('python程式設計')


if __name__ == '__main__':
    main()

python沒有從語言層面支援抽象類的概念
我們可以通過abc模組來製造抽象類的效果
在定義類的時候通過指定metaclass=ABCMeta可以將類宣告為抽象類
抽象類是不能建立物件的 抽象類存在的意義是專門拿給其他類繼承
abc模組中還有一個包裝器abstractmethod
通過這個包裝器可以將方法包裝為抽象方法 必須要求子類進行重寫
有抽象方法就是抽象類

#員工工資結算
from abc import ABCMeta,abstractclassmethod

class Employee(object,metaclass=ABCMeta):
    """員工"""
    def __init__(self,name):
        """初始化方法"""
        self._name = name


    @property
    def name(self):
        return self._name

    @abstractclassmethod
    def get_salary(self):
        pass


class Manager(Employee):

    def get_salary(self):
        return 15000


class Programmer(Employee):
    def __init__(self,name):
        super().__init__(name)
        self._working_hour = 0

    @property
    def working_hour(self):
        return self._working_hour

    @working_hour.setter
    def working_hour(self,working_hour):
        self._working_hour = working_hour\
            if working_hour>0 else 0

    def get_salary(self):
        return 150*self._working_hour

class Salesman(Employee):
    def __init__(self,name,sales=0):
        super().__init__(name)
        self._sales = sales

    @property
    def sales(self):
        return self._sales

    @sales.setter
    def sales(self,sales):
        self._sales = sales if sales>0 else 0

    def get_salary(self):
        return 1200+self._sales*0.05

def main():
    emps = [Manager('劉備'),Programmer('諸葛亮'),Manager('曹操'),
            Salesman('荀彧'),Salesman('呂布'),Programmer('張遼'),Programmer('趙雲')]

    for emp in emps:
        if isinstance(emp,Programmer):
            emp.working_hour = int(input('請輸入%s本月工作時間:'% emp.name))
        elif isinstance(emp,Salesman):
            emp.sales = float(input('請輸入%s本月銷售額:'% emp.name))
            #同樣是接收get_salary這個訊息,但是不同的員工表現出了不同的行為
            #因為三個子類都重寫了get_salary方法 所以這個方法會表現出多型行為
        print('%s本月工資為:¥%.2f元' %
              (emp.name,emp.get_salary()))


if __name__ == '__main__':
    main()
#建立銀行賬戶類

class Account(object):
    def __init__(self,*,card_number,owner,balance=0):
        self._card_number=card_number
        self._owner=owner
        self._balance=balance

    @property
    def balance(self):
        return self._balance

    def deposit(self,money):
        if money>0:
            self._balance += money
            return True
        return False

    def withdraw(self,money):
        if 0<money<=self._balance:
            self._balance -= money
            return True
        return False

    def transfer(self,other,money):
        if self.withdraw(money):
            other.deposit(money)
            return True
        return False


def main():
    account = Account(card_number='1234567',owner='熊彪')
    print(account.balance)
    account.deposit(2000)
    account.withdraw(500) #Account.withdraw(account,500)
    print(account.balance)
    if account.withdraw(5000):
        print(account.balance)
    else:
        print('餘額不足')
    account2 = Account(card_number='233443222',owner='陳晨',balance=120)
    if account.transfer(account2,800):
        print(account.balance)
        print(account2.balance)
    else:
        print('轉賬失敗')



if __name__ == '__main__':
    main()
#建立分數類並且可以做加減乘除運算
from math import gcd

class Fraction(object):

    def __init__(self,num,den):
        if den == 0:
            raise ValueError('分母不能為0')
        self._den = den
        self._num = num
        self.normalize()
        self.simplify()

    @property
    def num(self):
        return self._num

    @property
    def den(self):
        return self._den

    def add(self,other):
        return Fraction(self._num*other.den+self._den*other.num,self._den*other.den)\
            .simplify().normalize()

    def sub(self,other):
        return Fraction(self._num*other.den-self._den*other.num,self._den*other.den)\
            .simplify().normalize()

    def mul(self,other):
        return Fraction(self._num*other.num,self._den*other.den).simplify().normalize()

    def div(self,other):
        return Fraction(self._num*other.den,self._den*other.num).simplify().normalize()
#運算子重寫:
    def __add__(self, other):
        return self.add(other)

    def __sub__(self, other):
        return self.sub(other)

    def __mul__(self, other):
        return self.mul(other)

    def __truediv__(self, other):
        return self.div(other)

    def simplify(self):
        """化簡"""
        if self._num != 0 and self._den != 1:
            factor = gcd(abs(self._num),abs(self._den))
            if factor > 1:
                self._num //= factor
                self._den //= factor
        return self


    def normalize(self):
        """正規化分數"""
        if self._den < 0:
            self._num = -self._num
            self._den = -self._den
        return self


    def __str__(self):
        if self._num == 0:
            return '0'
        elif self._den == 1:
            return str(self._num)
        else:
            return '%d/%d' %(self._num,self._den)


def main():
    f1 = Fraction(3,2)
    f2 = Fraction(5,4)
    print(f1+f2)
    print(f1-f2)
    print(f1*f2)
    print(f1/f2)



if __name__ == '__main__':
    main()
#建立撲克牌類


from  random import  randrange

class Card(object):
    """一張牌"""
    def __init__(self,suite,face):
        self._suite = suite
        self._face = face

    @property
    def face(self):
        return self._face

    @property
    def suite(self):
        return self._suite

    def __str__(self):
        if self._face == 1:
            face_str = 'A'
        elif self._face == 11:
            face_str = 'J'
        elif self._face == 12:
            face_str = 'Q'
        elif self._face == 13:
            face_str = 'K'
        else:
            face_str = str(self._face)
        return '%s%s' %(self._suite,face_str)



class Poker(object):
    """一副牌"""
    def __init__(self):
        self._cards = []
        self._current = 0
        for suite in  '♠♥♣♦':
            for face in range(1,14):
                card = Card(suite,face)
                self._cards.append(card)

    @property
    def cards(self):
        return self._cards

    def shuffle(self):
        """洗牌"""
        self._current = 0
        cards_len = len(self._cards)
        for index,card in enumerate(self._cards):
            pos = randrange(cards_len)
            self._cards[index],self._cards[pos] = \
                self._cards[pos],self._cards[index]

    @property
    def next(self):
        """發牌"""
        card = self._cards[self._current]
        self._current += 1
        return card

    @property
    def has_next(self):
        """還有沒有牌"""
        return self._current<len(self._cards)

class Player(object):

    def __init__(self,name):
        self._name = name
        self._cards_on_hand = []
    @property
    def name(self):
        return self._name

    @property
    def cards_on_hand(self):
        return self._cards_on_hand

    def get(self,card):
        self._cards_on_hand.append(card)

    def arrange(self):
        self._cards_on_hand.sort(key=get_key)

def get_key(card):
    return card.face

def main():
    p = Poker()
    p.shuffle()
    players = [Player('東邪'),Player('西毒'),Player('南帝'),Player('北丐')]
    for _ in range(13):
        for player in players:
            player.get(p.next)
    for player in players:
        print(player.name + ':',end=' ')
        player.arrange()
        for card in player.cards_on_hand:
            print(card,end='')
        print()
if __name__ == '__main__':
    main()
用pygame做的五子棋遊戲
import  pygame

EMPTY = 0
BLACK = 1
WHITE = 2
black_color = [0,0,0]
white_color = [255,255,255]
class RenjuBoard(object):

    def __init__(self):
        self._board = [[]]*15
        self.reset()

    def reset(self):
        for row in range(len(self._board)):
            self._board[row] = [EMPTY]*15

    def move(self,row,col,is_black):
        if self._board[row][col] == EMPTY:
            self._board[row][col] = BLACK if is_black else WHITE
            return True
        return False

    def draw(self,screen):
        for index in range(15):
            pygame.draw.line(screen, black_color, [20, 20 + 40 * index], [580, 20 + 40 * index], 1)
            pygame.draw.line(screen, black_color, [20 + 40 * index, 20], [20 + 40 * index, 580], 1)
        pygame.draw.rect(screen, black_color, [16, 16, 568, 568], 4)
        pygame.draw.circle(screen, blac