python 学习笔记7
类和对象
对象:指某个具体的东西,描述这个东西可以用其静态的属性(属性)+动态的行为(方法),把这些零散的东西封装成一个整体,就是对象。
类:某一个具体的对象的抽象,相当于是对象的图纸,使对象达到量产的效果。
面向过程:在解决问题的时候,主要关注解决问题的每一个步骤。
面向对象:在解决问题的时候,关注解决问题所需要的对象。
python是一门彻底的面向对象的语言。
面向对象其实是面向过程的封装,将不同的的过程包装给一个或几个对象。
类定义出来后,其和类对象互相绑定,并不会因为实例对象的改变而改变
当实例对象的属性/方法改变时,会创造一个新的同名属性/方法覆盖原来的属性/方法。为了避免重名,尽量不要在一个类中定义出所有能想到的属性/方法,也就是尽量拆分,然后通过组合或继承组合起来。
元类:创建类对象的类
类的创建
class Turtle: # python中的类名约定以大写字母开头
#属性
color = 'green' #这里给类添加了属性color,是给类添加属性的第一种方法,更常用
weight = 10
legs = 4
shell = True
mouth = '大嘴'
#方法
def climb(self):
print('climbing...')
def run(self):
print('running...')
def eat(self):
print('eating')
def sleep(self):
print('sleeping')
通过type来创建类
Dog = type("Dog",(),{'count': 0,"run":run}) #变量名Dog指向名为“Dog”的类,属性count = 0,方法run为run函数。
类的描述
生成类文档,给别人和自己以方便
class Person():
"""
这个类的描述,作用,构造函数等等;类的属性描述
Attribtues:
count: int 代表人的个数
"""
count = 1
def run(self,distance,step):
"""
方法的作用
:param distance: 参数的含义,类型,是否有返回值
:param setp:
:return: 返回值的含义,类型
"""
pass
查看类文档:
help(Person)
项目文档
将注释和描述集中,便于传输。
生成
方法①
使用pydoc模块
创建实例化对象/类的实例化
即通过类创建具体的对象的过程,就叫做类的实例化。
tt = Turtle() #通过Turtle这个类创建tt这个实例化对象
tt.climb() #climbing...
tt.run() #running...
属性
给对象添加/查找/修改/删除属性
我们给对象tt增加一个height属性
tt.height = 10
print(tt.__dict__) #{'height': 10},并没有打印Turtle中的其他属性,说明tt.climb()是通过对象访问类中的属性
把tt.height看成一个变量,就很容易能想到其查找、修改和删除的方法
print(tt.height) #通过tt.height查找属性对应的值
tt.height = 5 #将tt.height对应的值改到5
del tt.height #将tt.height这个属性删除
当访问对象一个不存在的属性时会报AttributeError。
给类添加/查找/修改/删除属性
添加、修改、删除:
Turtle.height = 15 #给Turtle类添加了一个height属性,给类添加属性的第二种方法
Turtle.height = 20 #修改
del Turtle.height #删除,只能删除自身的属性
查询:
tt = Turtle()
tt2 = Turtle()
tt.height = 10
Turtle.height = 15
print(tt2.height) #15
print(tt.height) #10,通过对象访问属性时优先访问对象的属性,没有再从类中找,再没有报错
del tt2.height #报错,不能通过对象删除类的属性,tt2自身又没有height属性。
这几种对类的操作中只有查询能通过对象对类的属性进行操作,其他都不行。
方法
实例方法、类方法和静态方法:根据接受参数的不同划分。实例方法的第一个参数是实例,类方法的第一个参数是类,静态方法没有第一个参数。
class Turtle:
def shilifangfa(self, *params]): #定义一个实例方法,self一定要有,这是一个规范
print("This is an instance method",self)
@classmethod #定义类方法需要用装饰器装饰
def leifangfa(cls):
print("This is a classmethod",cls)
@staticmethod #定义静态方法需要用装饰器装饰
def jingtaifangfa():
print("This is a static method")
class Bclass:
pass
三种方法都是存储在类对象里面,而不是存储在实例对象里面
调用:不同类型的方法有不同的调用方式
tt = Turtle()
tt2 = Bclass()
# 实例方法
tt.shilifangfa() #self = tt,通过实例对象tt调用时,tt作为第一个参数传入,标准的做法
Turtle.shilifangfa(tt) #通过类调用时,要加入实例参数,可以是非本类的实例
function = Turtle.shilifangfa()
function(tt2) #间接引用
# 类方法
Turtle.leifangfa() #cls = Turtle,Turtle作为第一个参数传入
Turtle.leifangfa()
Turtle.jingtaifangfa()
tt.jingtaifangfa() #静态方法可以通过实例对象或类调用
OO(Object Oriented)/面向对象的特征
OOP(Object Oriented Program):面向对象编程
OOA(Object Oriented Analysis):面向对象分析
OOD(Object Oriented Design):面向对象设计
1、封装
将一些方法打包进入一个类,不需要知道方法的机制,只需要知道方法的使用方式和效果就可以使用
2、继承
class DerivedClassName(BaseClassName):
class DerivedClassName(BaseClassName1,BaseClassName2,...): #多重继承
其中DerivedClassName为子类,BaseClassName为基类/父类/超类
子类可以继承父类的属性、方法。
多重继承时要谨慎,可能会出现不可预见的bug
class Parent:
def hello(self):
print("正在调用父类方法")
class Child(Parent):
pass
p = Parent()
p.hello() #正在调用父类方法
c = Child()
c.hello() #正在调用父类方法
如果子类定义与父类同名的方法或属性,会覆盖父类的方法或属性
class Child1(Parent):
def hello(self):
print("正在调用子类方法")
c1 = Child2()
c1.hello() #正在调用子类方法
同样,子类的初始化会将父类的初始化覆盖,为了解决这个问题,有两种方法:
①调用未绑定的父类方法
将父类的初始化写入子类中,就不会被子类覆盖(不用一行一行复制,这样太蠢了,虽然也可以)
import random
class Fish():
def __init__(self):
self.x = random.randint(0,10)
self.y = random.randint(0,10)
def move(self):
self.x -= 1
print("现在的位置是:",self.x,self.y)
class Shark(Fish):
def __init__(self):
Fish.__init__(self) #<--就是这一行使子类的初始化不会覆盖父类的初始化
self.hungry = True
def eat(self):
if self.hungry == True:
print('吃!!')
self.hungry = False
else:
print("嗝..饱了")
或者将子类的实例化对象丢到父类的初始化中去也可以实现
Fish.__init__(shark)
shark.move()
“绑定“请见后文
②使用super函数
python提供的一个更好的方法,super函数会自动搜寻父类并继承所有父类的方法,更全面,当父类有很多时会更方便
将Fish.__init__(self) 替换为super().__init__()
3、多态
不同对象对于同一方法的不同相应
class A:
def fun(self):
print('我的小A')
class B:
def fun(self):
print('我的小B')
a = A()
b = B()
a.fun() #‘我是小A’
b.fun()#‘我是小B',不同对象对于同一方法的实现不同,这就是多态
4、What is self?
Python的self相当于C++的this指针
由同一个类可以生成无数个对象,对象会将self作为第一个参数传入,因此虽然不同对象有相同的方法,但是不同的对象会有不同的实现,就是self在起作用,即将对象自身作为参数传入。
class Ball():
def setname(self,name):
self.name = name
def kick(self):
print('我是%s' % self.name)
a = Ball()
b = Ball()
c = Ball()
a.setname('sa')
b.setname('sb')
c.setname('ca')
a.kick() #我是sa
b.kick() #我是sb
c.kick() #我是ca
5、__init__(self,param1,param2)
对象本身即可作为一个方法,定义__init__(self,param1,param2):——>可调用Ball(param1,param2):,在某些程度上更加方便
class Ball:
def __init__(self,name):
self.name = name
def kick(self):
print('我是%s' % self.name)
a = Ball('sa') #更加方便
a.kick() #我是sa
6、私有和公有
同一个类定义出来的对象中的方法是公有的,但也要有私有的,即同一个类定义出的对象的方法不同,Python并没有真正的私有化支持,但是,可以使用下划线完成伪私有效果。对类属性/方法和实例属性/方法有相同的规则
不加下划线
表示属性为公有属性
class Person:
__name = 'John' #'__'将name变量名改为了'_类名__变量名',本例子中为'_Person__name'
def getName(self):
return self.__name
p.name #报错
p.__name #报错
p.getName() #John,Python中的私有变量为伪私有,仍可以被外部调用。
7、组合
建一个水池,其中要有乌龟和鱼,用水池继承乌龟和鱼就会很奇怪。所谓组合就是把两个类的实例化放在一个新类中去。
class Turtle:
def __init__(self,x):
self.num = x
class Fish:
def __init__(self,x):
self.num = x
class Pool:
def __init__(self,x,y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("there are %d turtles and %d fish in the pool" %(self.turtle.num,self.fish.num))
调用:
pool = Pool(1,10)
pool.print_num() #there are 1 turtles and 10 fish in the pool
8、绑定
Python严格要求方法需要有实例才能被调用,这就是绑定
当我们修改一个对象所绑定的类的时候:
tt = Turtle()
tt = Money() #第一种做法
tt.__class__ = Money #第二种做法
这样,当我们访问tt的属性的时候,如果tt中有这个属性,则访问,如果没有,则访问tt所指向的类(Money)中的属性。类中的属性相当于是其所绑定的对象的共同属性,而对象中的属性则是其特有的属性
9、相关BIF
① issubclass(class,classinfo):如果class是classinfo的子类就返回True,否则抛出TypeError。注意:一个类可以被认为是自身的子类;class,classinfo可以是元组
②isinstance(object,classinfo):检查实例对象object是不是属于类classinfo,是则返回True,否则返回False,如果第一个参数不是实例对象,则返回False,如果后一个参数不是类,则报出TypeError。
③hasattr(object,‘name’):检查object中是否有name属性,有则返回True
④getattr(object,‘name’[,default]):返回object中name属性值,如果指定的属性不存在,如果有设置default则返回default,否则报出AttributeError。
⑤setsttr(object,‘name’,value):与getattr类似,如果指定属性不存在则创建这个属性并附上value的值
⑥delattr(object,‘name’):删除实例对象的指定属性,如果属性不存在则抛出AttributeError的异常。
⑦property(fget =None,fset = None, fdel = None,doc = None):设置属性,其中fget,fset,fdel分别为类中获得属性的方法、设置属性的方法和删除属性的方法。
class C:
def __init__(self,size = 10):
self.size = size
def getsize(self):
return self.size
def setsize(self,value):
self.size = value
def delsize(self):
del self.size
x = property(getsize, setsize, delsize)
c1 = C()
c1.x #即c1.getsize(),输出10
c1.x = 18 #即c1.setsize(18)
del c1.x #即c1.delsize()
元类查找机制
使用class创建类时,系统会检测类对象中是否有__mateclass__
属性,没有时检测父类中有没有__mateclass__
属性,再没有时再检测模块中有无__mateclass__
属性,再没有时才通过type这个元类来创建类对象。
指明元类:
class Person():
__metaclass__ = xxx
pass
或
class Person(metaclass = xxx):
pass