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