对象 = 属性(变量) + 方法(函数)
1. OO的特征
OO:Object Oriented(面向对象)
1. 封装:对外部隐藏对象的工作细节
一种信息隐蔽技术
例如:我们只会用list的相关方法,并不知道它们是如何实现的。
2. 继承:子类自动共享父类之间数据和方法的机制
3. 多态:可以对不同的对象调用相同的方法,产生不同的结果
即不同对象对同一方法响应不同的行动。
2.面向对象编程
1.self
每个实例对象的唯一标志,相当于C++的this指针。要求定义方法时把self写成第一个参数。
>>> class Ball:
def setName(self,name):
self.name = name
def kick(self):
print('I am %s' % self.name)
>>> a = Ball()
>>> a.setName('Tom')#调用时,会把a对应到self
>>> b = Ball()
>>> b.setName('John')
>>> a.kick()
I am Tom
>>> b.kick()
I am John
2.python的魔法方法
1. __init__(self):构造方法
实例化一个对象时,这个方法就在创建对象时被调用。
>>> class Ball:
def __init__(self,name):#重写init,添加了一个name参数。
self.name = name
def kick(self):
print('I am %s' % self.name)
>>> a = Ball('Tom')
>>> a.kick()
I am Tom
__init__特殊方法不应当返回除了None以外的任何对象,不能像下面这样写:
class C:
def __init__(self):
return 'hello world'
3.公有和私有
name mangling机制:在Python中定义私有变量只需要在变量名或函数名前加上“__”(两个下划线)即可。
>>> class Person:
__name = 'Tom'#name变成了私有,不能通过p.__name直接访问
def getName(self):#通过p.getName()间接访问
return self.__name
>>> p = Person()
>>> p.getName()
'Tom'
也可以通过“_类名__变量名”访问,但不提倡。即:
p._Person__name
3. 类和对象的创建
1.类的创建
class Turtle:
#属性
color = 'green'
weight = 10
legs = 4
shell = True
mouth = '大嘴'
#方法
def climb(self):
print('爬。。。。')
def run(self):
print('跑。。。。')
2.对象的创建
>>> tt = Turtle()#把类赋给一个实例tt
>>> tt.climb()#调用成员方法
爬。。。。
>>> tt.color#调用成员属性
'green'
>>> Turtle()#创建一个实例,不被引用,会被回收机制清空
<__main__.Turtle object at 0x02B40FF0>
3.一个问题
Paste_Image.png4.静态属性和静态方法
1.静态属性
在类中直接定义的变量(没有self),就是静态属性。引用类的静态属性使用“类名.属性名”的形式。
例如,计算一个类被实例化的次数:
>>> class C:
count = 0
def __init__(self):
C.count += 1
def getCount(self):
return C.count
>>> a = C()
>>> b = C()
>>> C.count
2
2.静态方法
定义方法:在定义方法前加上@staticmethod。
优点:不会绑定到实例对象上,节省开销。
>>> class C:
@staticmethod
def static(a,b,c):
print(a,b,c,a+b+c)
def nostatic(self):
print('I am nostatic.')
>>> c = C()
>>> c.static == C.static
True
>>> c.nostatic == C.nostatic
False
5.继承
1.继承的定义
class DerivedClassName(BaseClassName):
.......
其中,BaseClassName为父类、基类或超类,DerivedClassName为子类。子类可继承父类的属性和方法。
例如:
>>> class Parent:
def hello(self):
print('正在调用父类的方法。')
>>> class Child(Parent):
pass
>>> c = Child()
>>> c.hello()
正在调用父类的方法。
2.方法覆盖
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。
>>> class Child(Parent):
def hello(self):
print('正在调用子类的方法。')
>>> 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
return (self.x,self.y)
class Shark(Fish):
def __init__(self):
hungry = True
s = Shark()
s.move()#会报错,因为子类重写了父类的init方法
实现方法覆盖有两种方法:
- 调用未绑定的父类方法
class Shark(Fish):
def __init__(self):
Fish.__init__(self)#这里的self是子类的实例
hungry = True
- 使用super()函数(推荐)
可以自动找到父类的方法,并自动传入self参数。
super的超级之处在于你不需要明确给出任何父类的名字,它会自动帮您找出所有父类以及对应的方法。由于不必给出基类名字,所以如果改变了类继承关系,只需改变class语句里的父类即可。
class Shark(Fish):
def __init__(self):
super().__init__()
hungry = True
3.多重继承
1.定义方法:
class DerivedClassName(Base1,Base2,...):
.......
尽量不用多重继承,防止不可预料的错误。
2.菱形继承
Paste_Image.pngclass A():
def __init__(self):
print("进入A…")
print("离开A…")
class B(A):
def __init__(self):
print("进入B…")
A.__init__(self)
print("离开B…")
class C(A):
def __init__(self):
print("进入C…")
A.__init__(self)
print("离开C…")
class D(B, C):
def __init__(self):
print("进入D…")
B.__init__(self)
C.__init__(self)
print("离开D…")
>>> d = D()
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…
解决方案(super函数大显神威):
class A():
def __init__(self):
print("进入A…")
print("离开A…")
class B(A):
def __init__(self):
print("进入B…")
super().__init__()
print("离开B…")
class C(A):
def __init__(self):
print("进入C…")
super().__init__()
print("离开C…")
class D(B, C):
def __init__(self):
print("进入D…")
super().__init__()
print("离开D…")
>>> d = D()
进入D…
进入B…
进入C…
进入A…
离开A…
离开C…
离开B…
离开D…
5.组合
组合常用于没有什么关系的几个类,是一种横向关系,而继承是一种纵向关系。
比如定义了一个乌龟类和小鱼类,又想定义一个水池类,包含上面两类,就用到了组合。
操作方法:直接在类定义中把需要的类放进去实例化就可以了。
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))
Paste_Image.png
6.类、类对象和实例对象
1.Python无处不对象,类本身也是对象。
>>> class C:
count = 0
>>> c = C()
>>> C.count += 1
>>> c.count
1
Paste_Image.png
2.如果实例的属性名字与方法名相同,则属性会覆盖方法。例:
>>> class C:
def c():
print('hello')
>>> x = C()
>>> x.c = 1
>>> x.c()
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
x.c()
TypeError: 'int' object is not callable
再如:
>>> class Test:
def __init__(self,x):
self.t = x
def t(self):
print('hello')
>>> tt = Test(10)
>>> tt.t#属性可以调用
10
>>> tt.t()#方法不能调用,被属性覆盖了
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
tt.t()
TypeError: 'int' object is not callable
- 不要在一个类里定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展
- 用不同的词性命名,如属性名用名词,方法名用动词。
3.区分类属性和实例属性
Paste_Image.png4.思考题
在一个类中定义一个变量,用于跟踪该类有多少个实例被创建。
class Lei:
count = 0
def __init__(self):
Lei.count += 1
def __del__(self):
Lei.count -= 1
a = Lei()
b = Lei()
print(Lei.count)
del a
print(Lei.count)
7.绑定
Python严格要求方法需要有实例才能被调用,这种限制就是Python所谓的绑定概念。
Paste_Image.png8.相关BIF
1.issubclass()
判断一个类是否是另一个类的子类:
issubclass(class,classinfo)
注意:
- 一个类它本身也被认为是它自己的子类。
- classinfo可以是类对象组成的元组,只要class是其中任何一个候选类的子类,则为真。
例如:
>>> class A:
pass
>>> class B(A):
pass
>>> issubclass(B,A)
True
>>> issubclass(B,B)
True
>>> issubclass(B,object)#object是所有类的父类
True
2.isinstance()
判断一个实例对象是否属于一个类。
isinstance(object,classinfo)
- 如果第一个参数不是对象,刚永远返回False。
- 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。例如:
>>> b = B()
>>> isinstance(b,B)
True
>>> isinstance(b,A)
True
>>> isinstance(b,(A,B))
3.hasattr()
判断一个对象是否有指定的属性。
hasattr(object,name)
例如:
>>> class C:
def __init__(self,x = 0):
self.x = x
>>> c = C()
>>> hasattr(c,'x')#注意,属性名要写成字符串形式
4.getattr()
得到一个对象的属性值。
getattr(object,name,[default])
如果属性不存在,则打印出default的内容。
例如:
>>> getattr(c,'x')
0
>>> getattr(c,'y','这个属性不存在。')
'这个属性不存在。'
5.setattr()
设置对象的属性值。如果属性不存在,则创建一个属性并赋值。
setattr(object,name,value)
>>> setattr(c,'y',3)
>>> getattr(c,'y')
3
6.delattr()
删除对象中指定属性。
delattr(object,name)
7.property()
用属性去设置属性。
property(fget=None,fset=None,fdel=None,doc=None)
例如:
>>> 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)
>>> c = C()
>>> c.x
10
>>> c.x = 11
>>> c.x
11
>>> del c.x
作用:
如果你改了get、set、del方法的名字,那提供给用户的接口也要改,麻烦。如果用了这个,改了也没关系,提供给用户的还是x。
网友评论