Python学习笔记之 面向对象
第一个python类
- 设计类
类名:见名之意,首字母大写,其他遵循驼峰原则
属性:见名之意,其他遵循驼峰原则
行为(方法/功能):见名之意,其他遵循驼峰原则
- 列如:
- 类名:Wife
属性:sex age height weight faceValue
行为:做饭 洗衣服 拖地 揉肩 捶腿
- 类名:Husband
属性:sex age height weight faceValue
行为:吃饭 看电视 打游戏 被揉肩 被捶腿
- 类名:Car
属性: color type
行为:跑
- 创建类
类:一种数据类型,本身并不占内存空间,根所学过的number,string,boolean等类似。用类创建实例化对象(变量),对象占内存空间
格式:
class 类名(父类列表):
属性
行为
# object:基类,超类,所有类的父类,一般没有合适的父类就写object
class Person(object):
#定义属性(定义变量)
name = ""
age = 0
height = 0
weight = 0
#定义方法(定义函数)
#注意:方法的参数必须以self当第一个参数
#self代表类的实例(某个对象)
def run(self):
print("run")
def eat(self, food):
print("eat" + food)
使用类实例化对象
- 实例化对象
格式: 对象名 = 类名(参数列表)
注意:没有参数,小括号也不能省略
class Person(object):
name = ""
age = 0
height = 0
weight = 0
def run(self):
print("run")
def eat(self, food):
print("eat" + food)
def openDoor(self):
print("我已经打开了冰箱门")
def fillEle(self):
print("我已经把大象装进冰箱了")
def closeDoor(self):
print("我已经关闭了冰箱门")
#实例化一个对象
per1 = Person()
print(per1)
print(type(per1))
print(id(per1))
per2 = Person()
print(per2)
print(type(per2))
print(id(per2))
访问对象的属性和方法
- 访问属性
格式:对象名.属性名
赋值:对象名.属性名 = 新值
class Person(object):
name = "stu"
age = 10
height = 160
weight = 90
def run(self):
print("run")
def eat(self, food):
print("eat " + food)
def openDoor(self):
print("我已经打开了冰箱门")
def fillEle(self):
print("我已经把大象装进冰箱了")
def closeDoor(self):
print("我已经关闭了冰箱门")
per = Person()
per.name = "tom"
per.age = 18
per.height = 160
per.weight = 80
print(per.name, per.age, per.height, per.weight)
class Person(object):
name = "stu"
age = 10
height = 160
weight = 90
def run(self):
print("run")
def eat(self, food):
print("eat " + food)
def openDoor(self):
print("我已经打开了冰箱门")
def fillEle(self):
print("我已经把大象装进冰箱了")
def closeDoor(self):
print("我已经关闭了冰箱门")
per = Person()
per.openDoor()
per.fillEle()
per.closeDoor()
per.eat("apple")
#问题:目前来看Person创建的所有对象属性都是一样的
per2 = Person()
print(per2.age)
per3 = Person()
print(per3.age)
对象的初始状态(构造函数)
构造函数:__init__() 在使用类创建对象的时候自动调用
注意:如果不显示的写出构造函数,默认会自动添加一个空的构造函数
class Person(object):
#name = "stu"
#age = 10
#height = 160
#weight = 90
def run(self):
print("run")
def eat(self, food):
print("eat " + food)
def __init__(self, name, age, height, weight):
#print(name, age, height, weight)
#定义属性
self.name = name
self.age = age
self.height = height
self.weight = weight
per = Person("hanmeimei", 20, 170, 55)
print(per.name, per.age)
per2 = Person("lilei", 21, 175, 70)
print(per2.name, per2.age)
per.run()
self
- self代表类的实例,而非类
哪个对象调用方法,那么该方法中的self就代表那个对象
self.__class__ 代表类名_
class Person(object):
def run(self):
print("run")
print(self.__class__)
p = self.__class__("tt", 30, 10, 30)
print(p)
def eat(self, food):
print("eat " + food)
def say(self):
print("Hello! my name is %s, I am %d years old" % (self.name, self.age))
#self不是关键字,换成其他的标识符也是可以的,但是帅的人都是用self
def play(a):
print("play " + a.name)
def __init__(self, name, age, height, weight):
self.name = name
self.age = age
self.height = height
self.weight = weight
per1 = Person("tom", 20, 160, 80)
per1.say()
per2 = Person("hanmeimei", 21, 160, 80)
per2.say()
per1.play()
per1.run()
析构函数
析构函数:__del__() 释放对象是自动调用
class Person(object):
def run(self):
print("run")
def eat(self, food):
print("eat " + food)
def __init__(self, name, age, height, weight):
self.name = name
self.age = age
self.height = height
self.weight = weight
def __del__(self):
print("这里是析构函数")
per = Person("hanmeimei", 20, 170, 55)
#释放对象
del per
#对象释放以后就不能再访问了
#print(per.age)
#在函数里定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费
def func():
per2 = Person("aa", 1, 1, 1)
func()
while 1:
pass
重写:将函数重写定义写一遍
__str__():在调用print打印对象时自动调用,是给用户用的,是一个描述对象的方法。
__repr__():是给机器用的,在Python解释器里面直接敲对象名在回车后调用的方法
注意:在没有str时,且有repr,str = repr
class Person(object):
def __init__(self, name, age, height, weight):
self.name = name
self.age = age
self.height = height
self.weight = weight
def __str__(self):
return "%s-%d-%d-%d" % (self.name, self.age, self.height, self.weight)
per = Person("hanmeimei", 20, 170, 55)
#print(per.name, per.age, per.height, per.weight)
print(per)
优点:当一个对象的属性值很多,并且都需要打印,重写了__str__方法后,简化了代码
访问限制
class Person(object):
def run(self):
print(self.__money)
print("run")
def eat(self, food):
print("eat " + food)
def __init__(self, name, age, height, weight, money):
self.name = name
self.__age__ = age
self._height = height
self.weight = weight
self.__money = money#_Person__money
#通过内部的方法,取修改私有属性
#通过自定义的方法实现对私有属性的赋值与取值
def setMoney(self, money):
#数据的过滤
if money < 0:
money = 0
self.__money = money
def getMoney(self):
return self.__money
per = Person("hanmeimei", 20, 170, 55, 100000)
#per.age = 10
#print(per.age)
#如果要让的内部属性不被外部直接访问,在属性前加两个下划线(__),在Python中如果在属性前加两个下划线,那么这个属性就变成了私有属性
#print(per.__money) #外部使用
#per.run() #内部可以使用
per.setMoney(10)
print(per.getMoney())
#不能直接访问per.__money是因为Python解释器把__money变成了_Person__money,仍然可以用_Person__money去访问,但是强烈建议不要这么干(帅的人都不这么干),不同的解释器可能存在解释的变量名不一致
per._Person__money = 1
print(per.getMoney())
#在Python中 __XXX__ 属于特殊变量,可以直接访问
print(per.__age__)
#在Python中 _XXX 变量,这样的实例变量外部是可以访问的,但是,按照约定的规则,当我们看到这样的变量时,意思是“虽然我可以被访问,但是请把我视为私有变量,不要直接访问我”
print(per._height)
单继承的实现
# 定义第一个类:
class Person(object):
def __init__(self, name, age, money):
self.name = name
self.age = age
self.__money = money
def setMoney(self, money):
self.__money = money
def getMoney(self):
return self.__money
def run(self):
print("run")
def eat(self, food):
print("eat " + food)
# 定义第一个继承类
from person import Person #引入Person类
class Student(Person):
def __init__(self, name, age, money, stuId):
#调用父类中的__init__
super(Student, self).__init__(name, age, money)
#子类可以有一些自己独有的属性
self.stuId = stuId
def stuFunc(self):
print(self.__money)
# 定义第二个继承类
from person import Person
class Worker(Person):
def __init__(self, name, age, money):
#调用父类中的__init__
super(Worker, self).__init__(name, age, money)
# 单继承的实现
from person import Person
from student import Student
from worker import Worker
per = Person("aa", 1, 2)
stu = Student("tom", 18, 12345, 110)
print(stu.name, stu.age)
stu.run()
print(stu.stuId)
#print(stu.__money)私有属性
print(stu.getMoney()) #通过继承过来的共有方法访问私有属性
#stu.stuFunc()
wor = Worker("lilei", 20, 111)
print(wor.name, wor.age)
wor.eat("apple")
print(per.getMoney())
多继承的实现
# 定义一个母亲类
class Mother(object):
def __init__(self, faceValue):
self.faceValue = faceValue
def eat(self):
print("eat")
def func(self):
print("func2")
# 定义一个父亲类
class Father(object):
def __init__(self, money):
self.money = money
def play(self):
print("play")
def func(self):
print("func1")
# 定义一个小孩类
from Father import Father
from Mother import Mother
class Child(Father, Mother):
def __init__(self, money, faceValue):
#写法
Father.__init__(self, money)
Mother.__init__(self, faceValue)
# 多继承的实现 调用
from Child import Child
def main():
c = Child(300, 100)
print(c.money, c.faceValue)
c.play()
c.eat()
#注意:父类中方法名相同,默认调用的是在括号中排前面的父类中的方法
c.func()
if __name__ == "__main__":
main()
多态
# 定义一个动物类
class Animal(object):
def __init__(self, name):
self.name = name
def eat(self):
print(self.name + "吃")
# 定义一个猫类
from animal import Animal
class Cat(Animal):
def __init__(self, name):
#self.name = name
super(Cat, self).__init__(name)
# def eat(self):
# print(self.name + "吃")
# 定义一个老鼠类
from animal import Animal
class Mouse(Animal):
def __init__(self, name):
#self.name = name
super(Mouse, self).__init__(name)
# def eat(self):
# print(self.name + "吃")
# 定义一个人类
class Person(object):
'''
def feedCat(self, cat):
print("给你食物")
cat.eat()
def feedMouse(self, mouse):
print("给你食物")
mouse.eat()
'''
def feedAnimal(self, ani):
print("给你食物")
ani.eat()
# 多态 - 及调用
from cat import Cat
from mouse import Mouse
from person import Person
'''
多态:一种事物的多种形态
最终目标:人可以喂任何一种动物
'''
tom = Cat("tom")
jerry = Mouse("jerry")
tom.eat()
jerry.eat()
#思考:在添加100种动物,也都有name属性和eat方法
#定义了一个有name属性和eat方法的Animal类,让所有的动物类都继承自Animal
#定义一个人类,可以喂猫和老鼠吃东西
per = Person()
#per.feedCat(tom)
#per.feedMouse(jerry)
#思考:人要喂100种动物,难道要写100个feed方法吗??
#tom和jerry都继承自动物
per.feedAnimal(tom)
per.feedAnimal(jerry)
对象属性与类属性
class Person(object):
# 这里的属性实际上属于类属性(用类名来调用)
name = "person"
def __init__(self, name):
pass
#对象属性
self.name = name
print(Person.name)
per = Person("tom")
#对象属性的优先级高于类属性
print(per.name)
#动态的给对象添加对象属性
per.age = 18#只针对于当前对象生效,对于类创建的其他对象没有作用
print(Person.name)
per2 = Person("lilei")
#print(per2.age) #没有age属性
#删除对象中的name属性,在调用会使用到同名的类属性
del per.name
print(per.name)
#注意:以后千万不要讲对象属性与类属性重名,因为对象属性会屏蔽掉类属性。但是当删除对象属性后,在使用又能使用类属性了。
动态给实例添加属性和方法并使用__slots__
from types import MethodType
#创建一个空类
class Person(object):
__slots__ = ("name", "age", "speak")
per = Person()
#动态添加属性,这体现了动态语言的特点(灵活)
per.name = "tom"
print(per.name)
#动态添加方法
'''
def say(self):
print("my name is " + self.name)
per.speak = say
per.speak(per)
'''
def say(self):
print("my name is " + self.name)
per.speak = MethodType(say, per)
per.speak()
#思考:如果我们想要限制实例的属性怎么办?
#比如,只允许给对象添加name,age,height,weight属性
#解决:定义类的时候,定义一个特殊的属性(__slots__),可以限制动态添加的属性
per.height = 170
print(per.height)
class Person(object):
def __init__(self, name, age):
#属性直接对外暴露
#self.age = age
#限制访问
self.__age = age
self.__name = name
def getAge(self):
return self.__age
def setAge(self, age):
if age < 0:
age = 0
self.__age = age
#方法名为受限制的变量去掉双下划綫
@property
def age(self):
return self.__age
@age.setter #去掉下划线.setter
def age(self, age):
if age < 0:
age = 0
self.__age = age
@property
def name(self):
return self.__name
@name.setter # 去掉下划线.setter
def name(self, name):
self.__name = name
per = Person("sunck", 18)
#属性直接对外暴露
#不安全,没有数据的过滤
#per.age = -10
#print(per.age)
#使用限制访问,需要自己写set和get方法才能访问
#per.setAge(15)
#print(per.getAge())
per.age = -100 #相当于调用setAage
print(per.age) #相当于调用getAge
print(per.name)
#property:可以让你对受限制访问的属性使用点语法
# 定义一个弹夹类
class BulletBox(object):
def __init__(self, count):
self.bulletCount = count
# 定义一个枪类
class Gun(object):
def __init__(self, bulletBox):
self.bulletBox = bulletBox
def shoot(self):
if self.bulletBox.bulletCount == 0:
print("没有子弹了")
else:
self.bulletBox.bulletCount -= 1
print("剩余子弹:%d发" % (self.bulletBox.bulletCount))
# 定义一个人类
class Person(object):
def __init__(self, gun):
self.gun = gun
def fire(self):
self.gun.shoot()
def fillBullet(self, count):
self.gun.bulletBox.bulletCount = count
# 调用
from person import Person
from gun import Gun
from bulletbox import BulletBox
'''
人
类名:Person
属性:gun
行为:fire
枪
类名:Gun
属性:bulletBox
行为:shoot
弹夹
类名:BulletBox
属性:bulletCount
行为:
'''
#弹夹
bulletBox = BulletBox(5)
#枪
gun = Gun(bulletBox)
#人
per = Person(gun)
per.fire()
per.fire()
per.fire()
per.fire()
per.fire()
per.fire()
per.fire()
per.fillBullet(2)
per.fire()
per.fire()
per.fire()
执行调用这个程序得到结果:
剩余子弹:4发
剩余子弹:3发
剩余子弹:2发
剩余子弹:1发
剩余子弹:0发
没有子弹了
没有子弹了
剩余子弹:1发
剩余子弹:0发
没有子弹了
网友评论