Python学习 第四章 面向对象设计


第一章 函数、模块、包
第二章 数据类型
第三章 控制结构
第五章 图形界面设计

第四章 面向对象设计

1 定义和使用类

1.1 定义类

  每个对象都有一个类型,类是创建对象实例的模板,是对对象的概括,它包含对所创建对象的属性描述和行为特征的定义,相当于一个模板。

  在创建类时用变量形式表示的对象属性称为数据成员或属性(成员变量),用函数形式表示的对象行为称为成员函数(成员方法),成员属性和成员方法统称为类的成员。

格式:

class 类名:
	属性(成员变量)
	属性
	...
	成员函数
#  定义Person类
class Person:
    num = 1
    def SayHello(self):
        print('Hello!')

类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

1.2 创建对象

对象是类的实例,定义具体对象后,可以通过“对象名.成员”访问其中的数据成员或成员方法。

对象名 = 类名

p = Person()
p.SayHello()

2 构造函数__init__()

  类有一个名为 _ _ init _ _() 的特殊方法(构造方法,以两个下划线开头和结束),该方法在类实例化时会自动调用。

  构造函数一般用于对象数据成员设置初值或进行其他必要的初始化工作。用户未涉及构造函数,Python将会提供一个默认的构造函数。

class Complex:
    def __init__(self,realpart,imagpart):
        self.r = realpart
        self.i = imagpart
x = Complex(3.0,-4.5) #类实例化,会自动调用 __init__() 方法
print(x.r,x.i)

运行结果:
在这里插入图片描述

3 析构函数__del__()

  用来释放对象占用的资源,当对象被销毁的时候自动调用,使用del删除,即对象被销毁

class Complex:
    def __init__(self,realpart,imagpart):
        self.r = realpart
        self.i = imagpart
    def __del__(self):
        print("Complex不存在")
x = Complex(3.0,-4.5)
print(x.r,x.i)
print(x)
del x  

在这里插入图片描述
在执行“del x”语句后,系统自动调用析构函数,输出“Complex不存在”

4 实例属性和类属性

实例属性:在构造函数__init__()中定义的,定义时以self作为前缀;

类属性:在类中(方法之外)定义的属性。

在主程序中(类的外部),实例属性属于实例(对象),只能通过对象名来访问;

类属性属于类,可以通过类名访问,也可以通过对象名访问,为类的所有实例共享。

class Person:
    num = 1     #类属性(类变量)
    def __init__(self,str,n):   #构造方法
        self.name = str     #实例属性
        self.age = n
    def SayHello(self):      #成员方法(成员函数)   
        print("Hello!")
    def PrintName(self):
        print("姓名:",self.name,'年龄:',self.age)
    def PrintNum(self):
        print('num:',Person.num)
        
P1 = Person("Andy",22)
P2 = Person("Lily",23)

P1.PrintNum()
print(P1.name)      #对象访问实例变量name
P1.PrintName()

P2.PrintNum()
print(P2.name)
P2.PrintName()

Person.num = 2      #修改类属性
print('num:',Person.num)        #类访问类变量num

在这里插入图片描述
还可以动态地为类和对象增加成员

5 私有成员和公有成员

  1. Python并没有对私有成员提供严格的访问机制。
  2. 在定义类的属性时,如果属性名以两个下划线开头,表示私有属性,否则是公有属性。
  3. 私有属性在类的外部不能直接访问,需要通过调用对象的公有成员方法来访问,或者通过Python支持的特殊方式来访问
  4. Python提供了访问私有属性的特殊方式,可用于程序的测试和调试,对于成员方法也具有同样的性质

对象名._类名+私有成员

私有属性是为了数据封装和保密而设的属性,一般只能在类的成员方法(类的内部)中使用访问,不推荐从外部直接访问类的私有成员。

class Car:
    price = 100000      #定义类属性
    def __init__(self,c,w):     #构造方法
        self.color = c      #定义公有属性color
        self.__weight = w   #定义私有属性__weight
car1 = Car('Red',10.5)
print(car1.color)
print(car1._Car__weight)
print(car1.__weight)    
#AttributeError: 'Car' object has no attribute '__weight'

在这里插入图片描述

6 方法

self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。

self代表类的实例,而非类,类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

  1. 公有方法:只有实例化之后才能被调用
  2. 私有方法:只能在类的内部调用 ,不能在类的外部调用,私有方法的定义和私有属性定义都是一样的,在方法前面加上’__'双下划线就可以了;
  3. 静态方法:相当于"全局函数",可以被类直接调用,可以被所有实例化对象共享,通过staticmethod()定义静态方法没有"self"语句
    例:
#%%方法
class Fruit:
    price = 0   #类变量
    def __init__(self):     #构造方法
        self.__color = 'Red'    #定义和设置私有属性color
        self.__city = 'Gansu'   
    def __outputColor(self):     #定义私有方法
        print(self.__color)     #访问私有属性color
    def __outputCity(self):
        print(self.__city)
    def output(self):       #定义公有方法output()
        self.__outputColor()    #调用私有方法
        self.__outputCity()
    @ staticmethod
    def getPrice():         #定义静态方法getPrice()
        return Fruit.price
    @ staticmethod
    def setPrice(p):
        Fruit.price = p

7 继承

子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。

格式:

class 派生类名(基类名):
  派生成员

BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:

class 派生类名(模块名.基类名):

方法重写必须出现在继承中,指在派生类继承了基类的方法之后,如果基类方法的功能不能满足需求,需要对基类中的某些方法进行修改。

Python继承中的特点:

  1. 在继承中基类的构造函数不会被自动调用,需要在其派生类的构造中专门调用
  2. 通过“基类名.方法名()”,在派生类中调用基类的方法,且需要带上self参数变量,也可以使用内置函数super()
  3. Python总是先查找对应类型的方法,如果在派生类中找不到,才开始到基类中逐个查找。

例1:

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('ken',10,60,3)
s.speak()

在这里插入图片描述

例2:

import types
class Person(object):   #基类必须继承于object,否则在派生类中将无法使用super()函数
    def __init__(self,name = '',age = 20,sex = 'man'):
        self.setName(name)
        self.setAge(age)
        self.setSex(sex)
    def setName(self,name):
        if type(name)!=str:
            print('姓名必须是字符串')
            return
        self.__name=name
    def setAge(self,age):
        if type(age)!=int:
            print('年龄必须是数字')
            return
        self.__age = age
    def setSex(self,sex):
        if sex!='男'and sex!='女':
            print('性别输入错误')
            return
        self.__sex=sex
    def show(self):
        print('姓名:',self.__name,'年龄:',self.__age,'性别:',self.__sex)
        


class Student(Person):
    def __init__(self,name='',age=20,sex='man',schoolyear=2016):
        super(Student,self).__init__(name,age,sex)
        #Person.__init__(self,name,age,sex)
        self.setSchoolyear(schoolyear)
    def setSchoolyear(self,schoolyear):
        self.__schoolyear = schoolyear
    def show(self):
        Person.show(self)
        #super(Student,self).show()
        print('入学年份:',self.__schoolyear)
        
        

zhangsan=Person('张三',19,'男')
zhangsan.show()
zhangsan.setAge(22)
zhangsan.show()

lisi=Student('李四',18,'男',2015)
lisi.show()

lisi.setAge(20)
lisi.show()

在这里插入图片描述

8 多态

开闭原则,对扩展开放,对修改封闭
某个基类的继承类,其类型即属于这个派生类,又属于基类

9 案例——扑克牌发牌程序

四名牌手打牌,计算机随机将52张牌(不含大小王)发给4位牌手,并在屏幕上显示每位牌手的牌

class Card():
    """ A playing card. """
    RANKS = ["A", "2", "3", "4", "5", "6", "7",
             "8", "9", "10", "J", "Q", "K"]     #牌面数字 1--13
    SUITS = ["梅", "方", "红", "黑"]            #梅为梅花,方为方钻,红为红心,黑为黑桃 

    def __init__(self, rank, suit, face_up = True):
        self.rank = rank                #指的是牌面数字 1--13
        self.suit = suit                #suit指的是花色 
        self.is_face_up = face_up       #是否显示牌正面,True为正面,False为牌背面

    def __str__(self): #print()
        if self.is_face_up:
            rep = self.suit + self.rank #+" "+ str(self.pic_order())  
        else:
            rep = "XX"
        return rep

    def flip(self):                     #翻牌方法
        self.is_face_up = not self.is_face_up
        
    def pic_order(self):                #牌的顺序号
        if self.rank=="A":
            FaceNum=1
        elif self.rank=="J":
            FaceNum=11       
        elif self.rank=="Q":
            FaceNum=12
        elif self.rank=="K":
            FaceNum=13
        else:
            FaceNum=int(self.rank) 
        if self.suit=="梅":
            Suit=1
        elif self.suit=="方":
            Suit=2
        elif self.suit=="红":
            Suit=3
        else:
            Suit=4
        return (Suit - 1) * 13 + FaceNum
      
class Hand( ):
    """ A hand of playing cards. """
    def __init__(self):
        self.cards = []

    def __str__(self):               #重写print()方法
        if self.cards:
           rep = ""
           for card in self.cards:
               rep += str(card) + "\t"
        else:
            rep = "无牌"
        return rep

    def clear(self):
        self.cards = []

    def add(self, card):
        self.cards.append(card)

    def give(self, card, other_hand):
        self.cards.remove(card)
        other_hand.add(card)

class Poke(Hand):
    """ A deck of playing cards. """
    def populate(self):                     #生成一副牌
        for suit in Card.SUITS:
            for rank in Card.RANKS: 
                self.add(Card(rank, suit))

    def shuffle(self):                      #洗牌
        import random
        random.shuffle(self.cards)          #打乱牌的顺序

    def deal(self, hands, per_hand = 13):    #发牌,发给玩家,每人默认13张牌   
        for rounds in range(per_hand):
            for hand in hands:
                
                    top_card = self.cards[0]
                    self.cards.remove(top_card)
                    hand.add(top_card)
               



if __name__ == "__main__":
    print("This is a module with classes for playing cards.")
    #四个玩家
    players = [Hand(),Hand(),Hand(),Hand()]
    poke1 = Poke()
    poke1.populate()                #生成一副牌
    poke1.shuffle()                 #洗牌
    poke1.deal(players,13)          #发给玩家每人13张牌
    #显示4位牌手的牌
    n=1
    for hand in players:
        print("牌手",n ,end=":")
        print(hand)
        n=n+1

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值