Python第九节:类的学习
本节将系统的讲解面向对象(也就所说的类),从类的基础概念、类的应用、类自身的方法等等方面来讲解
一、面向对象的基础概念
概念:一切事物皆对象,类就是把共有的属性和方法封装起来方便调用。说简单的就是一种格式规范,把自己想要的进行的格式整理,方便运行、调用、查找,使代码更加清晰明确
1、类的初认识(第一个类)
class Cat:
def eat(self):
print("小猫爱吃鱼")
tom = Cat() #创建类的实例对象
tom.eat() #通过实例调用类的方法
>>>>小猫爱吃鱼
2、类的基础结构(类的属性和方法)
class Cat:
i=“鱼” #这个定义在类下的变量,叫做类的变量、类的属性,也可以叫做类的全局变量
def eat(self): #这个叫做类的方法
j="小猫" #函数内的变量,也就是局部变量
print("%s爱吃%s"%(j,self.i))
print(self.m) #这是设置的一个外界赋值的类属性
tom = Cat() #创建类的实例对象
tom.m="掌声" #在外界设置属性是不会被调用的,因为外部调用相当从弄了一个对象
print(tom.i) #通过实例调用类的属性
tom.eat() #通过实例调类的普通方法
>>>>鱼
>>>>小猫爱吃鱼
3、self的定义和使用
定义:代表的是类的实例,只用在类的方法中。在类中,一个方法调用本身之外的方法和属性时,都用self.起头调用,且自身创建时也加上self,证明你是类的实例方法
class Cat:
i = "小猫" #类属性是需要加self
def eat(self): #函数括号中加self,认证为类的方法
j="鱼" #局部变量是不需要加self
print("%s爱吃%s"%(self.i,j)) #类的方法调用类属性,类的属性前需要加self 例如: self.i
def drink(self,m): #函数括号中参数要与self用逗号“,”隔开,且self必须在第一个位置
self.eat() #类的方法调用另一个类属性,被调用的类的方法前需要加self 例如: self.eat()
print("%s 要喝水"%m) #调用函数本身传入的参数是不需要加self
tom = Cat() #创建类的实例对象
tom.drink("狗")
>>>>小猫爱吃鱼
>>>>狗 要喝水
4、类的初始化方法
class Cat:
def __init__(self,age): # 建立实例对象时,会自动调用初始化方法 __init__
print("这是一个初始化方法") #只要建立实例对象,就回运行
self.name = "Tom"
self.age = age # self.属性名 = 属性的初始值( __init__括号内的参数)
def eat(self):
print("%s 爱吃鱼" % self.name)
tom = Cat(11) #调用类时,调用参数应该与初始化方法内参数一致(除self之外,self为对象本身)
print(tom.name,tom.age)
>>>>这是一个初始化方法
>>>>Tom 11
5、类中的del和srt方法的使用
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 来了" % self.name)
def __del__(self): #__del__:在程序运行结束之后,都会在结尾,按对象的个数和顺序,打印该函数对应的结果
print("%s 我去了" % self.name)
def __str__(self): #__str__:建立实例,就给实例返回了一个值,答应自身时,就会调用
return "我是小猫[%s]" % self.name # 必须返回一个字符串
tom = Cat("Tom") # tom 是一个全局变量
print(tom) #这时调用__str__
6、类中的私有和伪私有
class Women:
def __init__(self, name):
self.name = name #类属性的初始值,也相当类属性
self.__age = 18 #建立私有属性,两个下划线+名字
def __secret(self): #建立私有方法,两个下划线+名字
print("%s 的年龄是 %d" % (self.name, self.__age)) # 在对象的方法内部,是可以访问对象的私有属性的
xiaofang = Women("小芳")
print(xiaofang.__age) # 私有属性,在外界不能够被直接访问
xiaofang.__secret() # 私有方法,同样不允许在外界直接访问
print(xiaofang._Women__age) # 伪私有属性,在外界能够被直接访问,同类前加下划线
xiaofang._Women__secret() # 伪私有方法,同样允许在外界直接访问,同类前加下划线
二、面向对象的应用
定义:通过面向对象的三大特性讲的 继承、多态、封装
1、类的继承
定义:一个类继承一个类,被继承类的方法和属性,都会被调用。相当一个类的内容全部放入另一类中,有共同的方法和属性时,继承的类直接覆盖被继承的类(例如:A类继承了B类,以A类的内容为主,A类没有的内容,再去取B类的内容)
class Animal: #该类没有括号,叫做基类
def eat(self):
print("吃---")
def drink(self):
print("喝---")
class Dog(Animal): #这个用括号括的一个类,叫做继承类。括号内的类为父类,继承的基类
def bark(self):
print("汪汪叫")
def look(self):
print("看家")
def sleep(self):
print("睡---")
class XiaoTianQuan(Dog): #继承类也能被继续在继承,叫做再继承类,说明类具有传递性
def fly(self):
print("我会飞")
def look(self):
print("会打架")
def sleep(self):
print("睡觉打呼噜") #针对子类特有的需求,编写代码
super().bark() #保留有的方法1.使用 super(). 调用原本在父类中封装的方法
#Dog.bark(self) #保留有的方法2、父类名.方法(self).调用原本在父类中封装的方法
print("$%^*%^$%^#%$%") # 增加其他子类的代码
xtq = XiaoTianQuan() #创建类的实例对象
xtq.fly() #能调用自身方法
xtq.bark() #能调用继承类的方法
xtq.eat() #能调用原始类的方法
xtq.look() #自身和父类都有共同的方法,就自用自己的方法,不会用父类的,就是覆盖了父类的用法
xtq.sleep()
>>>>我会飞
>>>>汪汪叫
>>>>吃---
class A:
def test(self):
print("A --- test 方法")
def demo(self):
print("A --- demo 方法")
class B:
def demo(self):
print("B --- demo 方法")
class C(B, A): # 多继承可以让子类对象,同时具有多个父类的属性和方法,按顺序排列,B在A前面
pass
c = C()
c.test() #那个父类中有该方法,就那个父类中取
c.demo() #多个父类中有该方法,就取排在前面的优先取
print(C.__mro__) #确定C类对象调用方法的顺序
>>>>A --- test 方法
>>>>B --- demo 方法
>>>>(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
2、类的多态
定义:以“类名.属性名”或者“类名.方法名()”使用的,都是多态的表现。其实就将类的本身作为操作对象,用于赋值、传参、调用等等形式,一般都不用self关键字
class Dog(object): #object原生类,可以不填写,因为类的建立就继承他了
def __init__(self, name):
self.name = name
class XiaoTianDog(Dog):
def game(self):
print("%s 飞到天上去玩耍..." % self.name)
class Person(object):
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name)) #调用了一个类是属性,类名+属性名
dog.game() #调用了一个类的方法,类名+方法名()
# 1. 创建一个狗对象
wangcai = XiaoTianDog("飞天旺财") #继承了父类的初始方法,所以必须传值
# 2. 创建一个小明对象
xiaoming = Person("小明")
# 3. 让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai) #将一个实例对象,当参数传给另一个类的方法中
>>>>小明 和 飞天旺财 快乐的玩耍...
>>>>飞天旺财 飞到天上去玩耍..
总结:说明类的实例可以做为参数直接给调用,调用的还是类是属性和方法,这个多态的一种
class Tool(object):
count = 0 #
lis = []
age=18
def __init__(self, name):
self.name = name
lis = Tool.lis.append(name) # 创建一个实例,初始方法就执行一次,类属性执行也随之添加或递减变化
def yy(self):
print("gogogo")
@classmethod #classmethod这个关键字是用来定义类方法的,表明下面的方法是类方法
def show_tool_count(cls): #类方法的括号中用特性的cls字符来定义参数,表是类方法参数
print("工具对象的数量 %d" % cls.age) #可以访问实例属性/类属性,不能访问类的所以方法
@staticmethod #staticmethod这个关键字是用来定义静态方法的,表明下面的方法是静态方法
def run(): #静态方法的括号中是不需要特性关键字的
print("工具没有了...") # 不能访问实例属性/类属性和类的所以方法
def xx(self):
Tool.count += 1 # 创建一个实例,类的方法执行一次,就相当类遍历一次,类似循环,相当一个计数器
self.show_tool_count()
Tool.run() #静态方法和类方法,都可以被普通方法直接调用
# 1. 创建工具对象
tool1 = Tool("斧头").xx()
tool2 = Tool("榔头").xx()
print(Tool.count) # 在外面,类属性直接可以通过“类名.属性名”得到,类属性初始值不能用该形式
print(Tool.lis) # 类名.属性名 的外部调用是用来做执行实例的总数做计算的(递增或递减,有遍历的迹象)
Tool.run()
Tool.show_tool_count() #在外部调用时,类方法和静态类,可以通过类名调用或实例名调用,普通的类的方法只能通过实例调用
3、类的封装
定义:把需要实现的对用功能或一整条独立的流程,放在一个固定的类,方便自己的调用、查找。反正自己感觉可以对立的东西,都可以进行封装。封装是一种思维,需要东西进行独立,在不改变原代码的情况下
注意事项:我们往往封装好的功能,有时需要被其他功能调用,这时就需要文件跟文件之间的传递。这时就要用上,from xx import yy 的方式调用文件(xx:表示文件的路径,其中执行文件和被调用文件的共有路径可以省写,这些路径上不能出现汉字,yy:表示文件中了类名)
文件一: 绝对路径--C:\Users\86181\Desktop\sat\stety\123.py 内部有的类---Koeb,hhh
文件二: 绝对路径--C:\Users\86181\Desktop\gggtet\ddkk\123.py 内部有的类---www
需求:文件二中的www类需要调用文件一hhh类中方法和属性
文件开头输入:from sat.stety.123 import hhh
千万要主要绝对路径上不能出现汉字
三、函数的自身方法
1、类的反射
定义:主要是指程序可以访问、检查和修改它本身状态,或行为的一种自检能力
class Dad:
money = 10
def __init__(self,name,age,weith):
print("fuqing")
self.name=name
self.age=age
self.weith=weith
def His_son(self):
print("%s da er zi"%self.name)
d = Dad("alix",35,"150cm")
#hasattr(实例,字符串)
print(hasattr(d,'name'))#hasattr:判断类的数据属性是否在项目中
>>>>True
print(hasattr(d,'His_son'))#hasattr:判断类的函数属性是否在项目中
>>>>True
#getattr(实例,字符串,默认参数【错误时才填写,并调用】)、
print(getattr(d,"name"))#getattr:在项目中找到对应数据属性的值
>>>>alix
print(getattr(d,'His_son'))#getattr:在项目中找到对应函数属性的地址值
>>>><bound method Dad.His_son of <__main__.Dad object at 0x000001191235D7C8>>
print(getattr(d,"sdasdsa",'错啦'))#getattr:找不到属性时
>>>>错啦
#setattr(实例,key,value)
setattr(d,'sb','sasd')#添加数据属性
print(d.sb) >>>>sasd'
setattr(d,"age",27)#修改数据属性值
print(d.age) >>>>27
setattr(d,'func',lambda x:x+1)#添加函数属性
print(d.func(50)) >>>>51
#delattr(实例,字符串)只能删除数据属性
delattr(d,'sb')#删除数据属性值
print(d.__dict__) #__dict__:获取实例的所有属性
>>>>{'name': 'alix', 'age': 27, 'weith': '150cm', 'func': <function <lambda> at 0x000001190B2804C8>}
2、类的attr属性
class Foo:
x=1
def __init__(self,y):
self.y=y
def __getattr__(self, item):#调用类中不存在的属性时,才会触发这个方法
print("sdhjsahd")
print(item)
def __delattr__(self, item):#类中删除一个属性时,才会催发这个方法
print("ffdsdsa")
print(item)
def __setattr__(self, key, value):#只要建立对象就出发,这个方法,优先init执行
print("csfdf")
#self.key=value 这样会产生死递归
self.__dict__[key]=value #直接设置属性字典
3、类的修饰器
def dome(func):
print("==========")
func.x=1
func.y=2
return func
@dome #test=dome(test)
def test():
print("test")
test() #先执行装饰函数,在执行本身
@dome #Foo=dome(Foo)
class Foo:
pass
f=Foo()
print(f.x)