类
- 类(class):用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法,对象是类的实例
- 类是一个独立存放变量(属性,方法)的空间,它定义了该集合中每个对象共有的属性和方法
- 类由类名,属性(变量),方法(函数)组成,类名约定俗成用大驼峰
- 对象:通过类定义的数据结构实例,对象包括两个数据成员:变量(类变量和实例变量)和方法,对象是类的实例化
- 方法:类中定义的函数
- 变量在类中称为属性,但是类中的属性不仅仅只包含变量,函数等其他的对象也可以作为类的属性
- 类变量:类变量在整个实例化的对象中是共用的,类变量定义在类中且在函数体之外
- 函数是代码块的封装,类是函数的封装
- 类是一类事物的抽象,不是真是存在的,描绘了该类事物的共性
实例
- 实例变量:定义在方法中的变量,只作用于当前实例的类
- 实例化:创建一个类的实例,类的具体对象,对象是类的实例化
- 实例也是一个独立存放变量的空间,每一个实例都是一个独立的变量空间,不同实例之间的空间互相不可见
类创建
- 创建类:使用class语句来创建一个新类,class之后为类的名称并以冒号结尾:
- 定义在类里面,函数外面的变量是类全局
- 优先访问实例属性,再访问类属性
- 类属性:共性,实例属性:特性
案例1:
class Person(object): #定义类
#class Preson(object): 和class Person:一样
var1 = "直接封装在类中的变量" #类变量/属性
print(Person.var1)
Person.var2 = "后来封装在类中的变量" #在类外添加类属性
print(Person.var2)
p = Person() #类的实例化,相对于函数叫调用
a = p.var1
print(a) #类属性访问
print(p.var2)
案例2:
class Person(object):
pass
p1 = Person()
p2 = Person()
p1.var = "在实例中封装的变量" #对象添加的属性,它的空间是独立的
#实例属性,类和其他的实例访问不到
print(p1.var)
~~print(Person.var)~~ #类中找不到,不会去找实例中的
~~print(p2.var)~~ #p2没有,去找Person也没有
- 类里面函数之外的变量都称之为类属性,类里面的其他方法也可以访问
- 没加self的变量(并在函数里面)是普通变量,类里面其他函数访问不了
class Person(object):
def a(self): #加了self的,实例化成对象可用,不实例化不可用
print("hahaha")
def b(): #不加self的是类属性,实例化的对象不能调用,类可以直接调用
print("xixixi")
p = Person()
p.a() #Person.a()是错误的
Person.b() #p.b()是错误的
类的方法
- 实例本身就拥有的数据,要访问这些数据没必要从外面的函数去访问,可以直接在类的内部定义访问数据的函数,这样就把数据给封装起来了,这些封装数据的函数和类本身是关联起来的,我们称之为类的方法
- 通常,将默认会传入的那个参数命名为self,用来表示调用这个方法的实例对象本身
- 要定义一个方法,除了第一个参数是self外,其他和普通函数一样,要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入
- 封装的另一个好处是可以给类增加新的方法
- 案例1:
class Person(object):
def eat(self): #实例方法,实例可调用,类不可调用
print("{} is eating".format(self.name))
p1 = Person() #没有定义参数,不传参
p1.name = "xiaoming"
p2 = Person()
p2.name = "xiaohong"
p1.eat() #xiaoming is eating
p2.eat() # xiaohong is eating
- 在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
- 当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
- 案例2:
class Person(object):
def __init__(self,name): #对类Person定义了参数
self.name = name
def __str__(self):
return 'woshi%s' % self.name #打印类的调用时起作用
def eat(self): # 实例方法,实例可调用
print("{} is eating".format(self.name))
p = Person('xiaoming')
p1 = Person('xiaohong')
p1.eat() # xiaohong is eating
print(p) #woshixiaoming
- def init(self): #初始化函数
class Man(object):
def __init__(self,name,sex):
self.name = name #类属性
self.sex = sex #类属性
print("%s是个%s出生落地了" % (self.name,self.sex))
def cry(self):
print("%s哭了" % (self.name))
def laugh(self):
print("%s笑了" % self.name)
man = Man("xiaoli","girl")
man.cry()
#xiaoli是个girl出生落地了
xiaoli哭了
- 类里面凡是加了self的变量都称为类属性,className.属性名,类里面的其他方法也是可以访问的
- 函数里面没加self的就是普通变量,类里面其他函数访问不了
- 定义在类里面函数外面的变量,是类全局,函数都能调用
- 实例化对象既能访问实例属性,也能访问类属性
- 例子1
class Dog:
def __init__(self,color):
self.color = color
def call(self):
print(self.color)
print('wang')
def change_color(self,new_color):
print(self.color)
self.color = new_color
return f'new color is {self.color}'
wangcai = Dog('hei')
print(wangcai.color)
wangcai.color = 'bai'
print(wangcai.color)
wangcai.call()
print(Dog('bai').change_color('hong'))
#hei
bai
bai
wang
bai
new color is hong
self可以理解为实例化出来的对象,self.color相当于wangcai.color
- 例子2
class Dog:
def __init__(self,color):
self.color = color
def call(self):
print(self.color)
print('wang')
def change_color(self,new_color):
print(self.color)
self.color = new_color
print('new color is %s' % self.color)
def test(name):
name.change_color('green')
wangcai = Dog('hei')
print(wangcai.color)
wangcai.color = 'bai'
print(wangcai.color)
wangcai.call()
Dog('bai').change_color('hong')
a = test(wangcai) #参数是实例化的对象wangcai
#hei
bai
bai
wang
bai
new color is hong
bai
new color is green
- 例
class Home:
def __init__(self,area):
self.area = area
self.containsItem = [] #用于保存对象
def __str__(self):
msg = '家当前可用面积为:' + str(self.area) + '\n'
# if len(self.containsItem ) > 0:
msg += '家里的物品有:'
if len(self.containsItem) > 0:
for temp in self.containsItem:
msg += temp.name + ','
# break
msg = msg[:-1]
else:
msg += '没有任何东西'
return msg
def add_item(self,item):
if self.area > item.area:
self.containsItem.append(item)
self.area -= item.area
class Bed:
def __init__(self,name, area):
self.name = name
self.area = area
def __str__(self):
msg = self.name + '床的面积为:' + str(self.area)
return msg
home = Home(128)
print(home)
bed = Bed('席梦思',4)
print(bed)
home.add_item(bed)
print(home)
bed2 = Bed('硬板床',3)
print(bed2)
home.add_item(bed2)
print(home)
#家当前可用面积为:128
家里的物品有:没有任何东西
席梦思床的面积为:4
家当前可用面积为:124
家里的物品有:席梦思
硬板床床的面积为:3
家当前可用面积为:121
家里的物品有:席梦思,硬板床
骰子游戏
import random
class Game(object):
"""
骰子游戏
"""
def __init__(self,player1,player2):
self.player1 = player1
self.player2 = player2
print('游戏初始化成功,可以开始')
def start_game(self):
self.player1.cast()
self.player2.cast()
print(self.player1)
print(self.player2)
class Player(object):
"""
玩家信息和玩的动作
"""
def __init__(self,name,sex,*dice):
self.name = name
self.sex = sex
self.dices = dice #表示该玩家拥有的骰子元组
def cast(self):
"""
玩家的行为动作,摇骰子
:return:
"""
for dice in self.dices:
dice.move()
def guess_dice(self):
"""
猜点数,猜多少个多少点
:return:
"""
return (4,2) #4个2
def __str__(self):
play_dice_count_list = [self.dices[0].count, self.dices[1].count, self.dices[2].count]
return '%s摇的骰子点数是%s' % (self.name,str(play_dice_count_list))
class Dice(object):
"""
骰子
"""
def __init__(self):
"""
骰子点数
:param count:
"""
self.count = 0
def move(self):
"""
投的骰子的点数
:return:
"""
self.count = random.randint(1,6) #对应自己的职责,骰子就是生成一个数,统计点数的个数是玩家去算,不归骰子管
#游戏开始之前准备六颗骰子
d1 = Dice()
d2 = Dice()
d3 = Dice()
d4 = Dice()
d5 = Dice()
d6 = Dice()
#每次游戏需要两位玩家
p1 = Player('xiaoge','man',d1,d2,d3)
p2 = Player('na','girl',d4,d5,d6)
#一共玩五次游戏
for i in range(1,6):
print('第%d次游戏的情况------' % i)
game = Game(p1,p2)
game.start_game()
#第1次游戏的情况------
游戏初始化成功,可以开始
xiaoge摇的骰子点数是[4, 6, 3]
na摇的骰子点数是[5, 1, 5]
第2次游戏的情况------
游戏初始化成功,可以开始
xiaoge摇的骰子点数是[2, 3, 2]
na摇的骰子点数是[6, 4, 4]
第3次游戏的情况------
游戏初始化成功,可以开始
xiaoge摇的骰子点数是[1, 6, 3]
na摇的骰子点数是[5, 5, 5]
第4次游戏的情况------
游戏初始化成功,可以开始
xiaoge摇的骰子点数是[4, 2, 2]
na摇的骰子点数是[6, 4, 3]
第5次游戏的情况------
游戏初始化成功,可以开始
xiaoge摇的骰子点数是[6, 1, 6]
na摇的骰子点数是[4, 2, 2]
私有属性
-私有属性属于这个类,一般不要外面调用,保护起来
-Python中私有属性有两种,一个下划线_和两个下划线__
- 以一个下划线_开头,私有属性,可以在外面调用,约定俗成不在外面调用,不常用
- 以两个下划线__开头,强制私有属性,在外面调用不了,比一个下划线常用
- 案例
class User(object):
def __init__(self):
self.__password = '234232'#隐藏属性
print('%s' % self.__password)
def change_password(self,pw):
self.__password = pw
return '%s' % self.__password
u1 = User()
print(u1.change_password('666666'))
print(u1.__password) #此方法是错误的,私有属性在外面没法调用,但在类里面可以调用更改
#Traceback (most recent call last):
File "/home/xiaoge/web_prv/text.py", line 209, in <module>
print(u1.__password)
234232
AttributeError: 'User' object has no attribute '__password'
666666
继承
class A(object):
def play(self):
print("xixi")
class B(A):
pass
- 类继承:类的继承可以让子类将父类的全部方法和类属性继承过来(私有属性除外),在Python3中,默认继承object类
实例(类属性,类方法,静态方法)
- 例1
#class Woman(object):
class Woman(object): #效果同上行代码
face = 'beautiful' #类属性
def cry(self):
print("xiaoli哭了")
def laugh(self):
print("%s笑了" % self.name)
@classmethod #类方法一定要在方法上面加一个装饰器,类方法的参数woman代表当前的类
def change_face(cls): #约定俗成用cls,和上面约定俗成用self一样
cls.face = 'fun' #woman代表当前的类,所以可以更改类属性
@staticmethod #静态方法,也属于类,没有默认传递的参数,如果定义参数,调用时一定要传参,可以通过类对象,类调用
def test():
Woman.face = 'funny' #通过类名调用修改类属性
print('静态方法')
class Child(Woman):
def smile(self):
print("笑了")
self.cry()
print(Child.face) #beautiful #Child继承Woman的类属性face,可以直接通过类来访问,也可以通过类的对象来访问
child = Child()
child.cry() #xiaoli哭了
child.smile() #笑了
xiaoli哭了 #因为self调用了cry()方法 self.cry()
print(child.face) #beautiful #通过类的对象访问父类的类属性
child.face = 'beautifuller' #类属性要通过类修改,对象没法修改类属性,只是定义了一个对象属性name并赋值
print(child.face) #beautifuller
print(Child.face) #beautiful #通过类查看类属性发现类属性没被对象修改
Child.face = 'nice'
print(Child.face) #nice #子类只能修改自己的类属性,不能修改父类的类属性
print(Woman.face) #beautiful
print(child.face) #beautifuller
Woman.change_face()
print(Woman.face) #fun
Child.change_face() #类方法也可以被继承
print(Child.face) #fun
- 例2
class Animal(object): #父类
def __init__(self):
self.name = 'animal'
self.__name = 'animal0'
def eat(self):
print('吃')
def sleep(self):
print('睡')
class Dog(Animal): #Animal的子类
def __init__(self,name): #父类和子类都有的方法,子类优先调用自己的方法
self.name = name
def call(self):
print('汪汪叫')
class Cat(Animal): #Animal的子类
# def __init__(self): #如果对Cat进行初始化,Cat就调用自己的__init__,不会继承Animal的__init__方法,就会报错AttributeError: 'Cat' object has no attribute 'name',此处仍是方法的继承,不是属性的调用
# print('猫初始化了')
def catch(self):
print('抓老鼠')
class BoSiMao(Cat):
def meng(self):
print('卖萌')
wangcai = Dog('wangcai') #wangcai有三个功能,吃睡叫
wangcai.eat() #吃
print(wangcai.name) #wangcai
miao = Cat() #miao有三个功能,吃睡抓
print(miao.name) #animal
print(wangcai.__name) #AttributeError: 'Dog' object has no attribute '__name'
print(miao.__name) #AttributeError: 'Cat' object has no attribute '__name'
xiaomiao = BoSiMao()
print(xiaomiao.name) #animal #继承父类的父类的方法 此处类似多继承,也继承Cat也继承Animal
多继承
- 当继承多个父类时,如果父类中有相同的方法,那么子类会优先使用最先被继承的方法(第一个父类的)
- 当子类继承父类之后,如果子类不想使用父类的方法,可以通过重写来覆盖父类的方法
- 例
class A(object):
def test(self):
print('A')
class B(object):
def test(self):
print('B')
class C(A,B):
#class C(B,A): #如果这样写,B的优先级高于A
def test(self): #重写
print('C')
c = C()
c.test()
print(C.__mro__) #查看C的继承的优先级
#C
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
重写:
- 当子类重写父类方法之后,子类如果有想再次调用父类的方法,可以使用这两种方法:
- 方法一:
class C(A,B):
def play(self):
A.play(self)
print("这是C")
- 方法二:
class C(A,B):
def play(self):
super().play()
print("这是C")
super方法
- super函数可以调用父类的方法
- 在父类中也使用super函数后,可以通过调用类的mro方法属性来查看继承关系
- super函数可以来调用父类的方法,使用super的好处在于即使使用父类改变了,那么也不需要更改类中的代码
- 官方推荐super的用法如示例所示
- 在Python3中,类被创建时会自动创建方法解析顺序mro,可以通过类名.mro()来查看
- object是所有类的父类
- Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx
案例:
class XiaoMing(object):
def __init__(self):
self.height = 174
self.age = 48
self.money = 1000000000
def health(self):
print("身体非常好")
def money(self):
print("小明会赚钱")
class XiaoHong(object):
def __init__(self):
self.height = 160
self.age = 28
self.money = 100000
def appearance(self):
print("特别好看")
class XiaoQiang(XiaoMing,XiaoHong):
def __init__(self):
self.age = 2
def study(self):
print("小强学习好")
def money(self):
XiaoMing.money(self)
super().money()
print("小强会花钱")
son = XiaoQiang()
son.health() #身体非常好
son.appearance() #特别好看
son.study() #小强学习好
print(son.age) #2
print(XiaoMing().age) #实例化,48
son.money() #小明会赚钱
小明会赚钱
小强会花钱
print(XiaoQiang.__mro__)
#(<class '__main__.XiaoQiang'>, <class '__main__.XiaoMing'>, <class '__main__.XiaoHong'>, <class 'object'>)