目录
Python学习(八)
类和对象
面向对象编程
self是什么?
魔法方法
公有和私有
继承
多重继承
组合
类,类对象和实例对象
绑定
一些相关的BIF
对象 = 属性(变量,静态的) + 方法
类:可以批量的生产对象
Python是完全面向对象的语言,Object Oriented,具有以下特点:
类似this
>>> class Ball:
def setName(self,name):
self.name = name
def kick(self):
print('我是%s,谁踢我。。。' % self.name)
>>> a=Ball()
>>> a.setName('足球')
>>> b=Ball()
>>> b.setName('篮球')
>>> c=Ball()
>>> c.setName('土豆')
>>> a.kick()
我是足球,谁踢我。。。
_init_(self,param1,param2……)
类似构造方法。
重写这个方法实现初始化
>>> class Ball:
def __init__(self,name):
self.name=name
def kick(self):
print('我是%s,谁踢我。。。' % self.name)
>>> b=Ball('球')
>>> c=Ball()
Traceback (most recent call last):
File "", line 1, in
c=Ball()
TypeError: __init__() missing 1 required positional argument: 'name'
抛异常:TypeError: __init__() missing 1 required positional argument: 'name'
如下图:
在Python中定义私有变量只需要在变量名或函数名前加上“__”两个下划线,那么这个函数或变量就会为私有的了
>>> class Person:
__name = 'xiaomeili'
def getName(self):
return self.__name
>>> p=Person()
>>> p.__name #直接调用会抛出异常
Traceback (most recent call last):
File "", line 1, in
p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> p.getName()
'xiaomeili'
如下图:
实质上是:自动改写为_类名__变量名
>>> p._Person__name
'xiaomeili'
如下图:
所以Python的私有是伪私有,实质是没有权限控制的,可以被外部调用,只是调用的形式发生了变化。
class DerivedClassName(BaseClassName)
子类->基类,父类或超类
定义一个父类:
>>> class Parent:
def hello(self):
print('父类')
子类继承父类Person,便也有了hello方法:
>>> class Child(Parent):
pass
>>> c=Child()
>>> c.hello()
父类
如下图:
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性
import random as r
class Fish:
def __init__(self):
self.x = r.randint(0,10)
self.y = r.randint(0,10)
def move(self):
self.x -= 1
print('我的位置',self.x,self.y)
class Goldfish(Fish):
pass
class Carp(Fish):
pass
class Salmon(Fish):
pass
class Shark(Fish):
def __init__(self):
#这里重写了父类的init方法,不想父类方法被覆盖可以:调用未绑定的父类方法
Fish.__init__(self)
#或者使用super函数(推荐),如果多层继承,更方便。
super
self.hungry = True
def eat(self):
if self.hungry:
print('haha')
self.hungry = False
else:
print('吃饱了')
运行,调用:
>>> s = Shark()
>>> s.move()
我的位置 6 6
>>> s.hungry
True
>>> s.eat()
haha
>>> s.eat()
吃饱了
>>> class C(Base1,Base2):
pass
容易造成代码混乱,尽量避免使用
把没有继承关系的几个类组合,在一个类中实现其他类的实例
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('水池里总共有乌龟%d只,小鱼%d条!'%(self.turtle.num, self.fish.num))
运行输入:
>>> pool = Pool(1,10)
>>> pool.print_num()
水池里总共有乌龟1只,小鱼10条!
创建一个类C,a、b为类C的实例对象
>>> class C:
count = 0
>>> a = C()
>>> b = C()
>>> a.count
0
>>> b.count
0
>>> a.count += 10
>>> a.count
10
>>> b.count
0
而类C本身是类,也是一个对象,Python中无处不对象
>>> C.count += 100
>>> C.count
100
>>> a.count
10
>>> b.count
100
之前给a实例对象中的属性赋值了,所以a.count没有变。
总结:
注:
不要试图在一个类里边定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展
用不同的词性命名,如属性名用名词,方法名用动词
>>> class C:
def x(self):
print("X-man!")
>>> c = C()
>>> c.x()
X-man!
>>> c.x = 1
>>> c.x
1
>>> c.x()
Traceback (most recent call last):
File "", line 1, in
c.x()
TypeError: 'int' object is not callable
上述做法会抛出异常TypeError: 'int' object is not callable
Python严格要求方法需要有实例才能被调用,这种限制就是Python的绑定概念
创建一个类B
>>> class B:
def printB():
print("BBBBBBB")
用类对象直接调用
>>> B.printB()
BBBBBBB
然而,当把类实例化后,无法调用printB
>>> b = B()
>>> b.printB()
抛出异常TypeError: printB() takes 0 positional arguments but 1 was given
继续看,我们在创建一个类C:
>>> class C:
def setXY(self,x,y):
self.x = x
self.y = y
def printXY(self):
print(self.x,self.y)
创建类C的实例d,用__dict__查看属性,返回空字典
>>> d = C()
>>> d.__dict__
{}
直接用类对象调用,返回如下:
>>> C.__dict__
mappingproxy({'__module__': '__main__', 'setXY': , 'printXY': , '__dict__': , '__weakref__': , '__doc__': None})
调用setXY属性
>>> d.setXY(4,5)
>>> d.__dict__
{'x': 4, 'y': 5}
可以看到,实质上传入的是:d.setXY(d,4,5),所以这两个属性是只属于实例对象的, C.__dict__中没有,这也是self的作用
之后我们删除C
>>> del C
>>> e = c()
Traceback (most recent call last):
File "", line 1, in
e = c()
TypeError: 'C' object is not callable
报错TypeError: 'C' object is not callable,不能建立C的实例对象了
但是之前创建的d实例对象仍然可以调用x,y属性
>>> d.printXY()
4 5
issubclass(class,classinfo):检查一个类是否是另一个类的子类,是一种宽松的检查
>>> class A:
pass
>>> class B(A):
pass
>>> issubclass(B,A)
True
>>> issubclass(B,B)
True
>>> issubclass(B,object) #object是又有类的基类
True
isinstance(object,classinfo):检查一个实例对象是有属于一个类
hasattr(object,name):检查一个对象是否有指定的属性
>>> class C:
def __init__(self,x=0):
self.x = x
>>> c = C()
>>> hasattr(c,'x') #注意要用引号括起来
True
getattr(object,name[,default]):返回对象指定的属性值,如果不存在,可以配置默认人的返回值。
不指定的话,抛出异常AttributeError: 'C' object has no attribute 'y'
>>> getattr(c,'x')
0
>>> getattr(c,'y')
Traceback (most recent call last):
File "", line 1, in
getattr(c,'y')
AttributeError: 'C' object has no attribute 'y'
>>> getattr(c,'y','不存在')
'不存在'
setattr(object,name,value):设置对象中指定属性的值,如果对象不存在,新建一个属性,并赋值
>>> getattr(c,'y','不存在')
'不存在'
>>> setattr(c,'y','新属性')
>>> getattr(c,'y')
'新属性'
delttr(object,name):用于删除对象中指定的属性,如果属性不存在,抛异常AttributeError: p
>>> delattr(c,'p')
Traceback (most recent call last):
File "", line 1, in
delattr(c,'p')
AttributeError: p
Property(fget = None, fset = None, fdel = None, doc = None):通过属性设置属性,第一个参数是获取属性的方法,第二个参数是设置属性的方法,第三个参数是删除属性的方法。
按照上述的属性创建类C:
>>> 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)
之前要获取属性值,需要调用getSize(),现在只需x,删除x后,调用getSize()报错AttributeError: 'C' object has no attribute 'size'
>>> c = C()
>>> c.getSize()
10
>>> c.x
10
>>> c.x = 18
>>> c.x
18
>>> c.getSize()
18
>>> del c.x
>>> c.getSize()
Traceback (most recent call last):
File "", line 1, in
c.getSize()
File "", line 5, in getSize
return self.size
AttributeError: 'C' object has no attribute 'size'