Author
: Seven_0507
Date
: 2019-05-21
今天主要总结了Python面向对象编程的进阶知识点,主要从属性、类中的方法、运算符重载、类之间的关系、继承和多态方面归纳总结。
文章目录
Python面向对象进阶1. 类属性与实例属性1.1 类属性1.2 实例属性1.3 类属性和实例属性混合1.4 修改类属性和实例属性的区别
2. @property包装器3. __slots__魔法4. 类中的方法4.1 实例方法4.2 类方法4.3 静态方法
4. 运算符重载5. 类之间的关系5.1 关联关系5.2 依赖关系
6. 继承7. 多态
Python面向对象进阶
1. 类属性与实例属性
什么是类对象,实例对象
类对象:类名
实例对象:类创建的对象
1.1 类属性
class people:
name
= "Tom"
__age
= 18
p
= people
()
print(p
.name
)
print(people
.name
)
print(p
.__age
)
print(people
.__age
)
Tom
Tom
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-2-3efede2e003a> in <module>
8 print(people.name) # 类对象
9
---> 10 print(p.__age) #错误 不能在类外通过实例对象访问私有的类属性
11 print(people.__age) #错误 不能在类外通过类对象访问私有的类属性
AttributeError: 'people' object has no attribute '__age'
1.2 实例属性
class people:
name
= "tom"
p
= people
()
p
.age
= 18
print(p
.name
)
print(p
.age
)
print(people
.name
)
print(people
.age
)
tom
18
tom
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-0c71d7231365> in <module>
10
11 print(people.name) # 类属性,可以调用
---> 12 print(people.age) # 错误:实例属性,不能通过类对象调用
AttributeError: type object 'people' has no attribute 'age'
1.3 类属性和实例属性混合
class people:
name
="tom"
def __init__(self
,age
):
self
.age
=age
p
=people
(18)
p
.sex
="男"
print(p
.name
)
print(p
.age
)
print(p
.sex
)
print(people
.name
)
print(people
.age
)
print(people
.sex
)
tom
18
男
tom
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-3ef77090faf8> in <module>
13
14 print(people.name) # 类对象
---> 15 print(people.age) # 错误:实例属性,不能通过类对象调用
16 print(people.sex) # 错误:实例属性,不能通过类对象调用
AttributeError: type object 'people' has no attribute 'age'
1.4 修改类属性和实例属性的区别
"""
如果在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,
会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且如果通过
实例对象引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性
"""
class Animal:
name
= "Panda"
print(Animal
.name
)
p
= Animal
()
print(p
.name
)
p
.name
= "dog"
print(p
.name
)
print(Animal
.name
)
del p
.name
print(p
.name
)
Panda
Panda
dog
Panda
Panda
2. @property包装器
"""
--(1) 使用原有有方法定义访问器/修改器/删除器
"""
class Car(object):
def __init__(self
, brand
, max_speed
):
self
.set_brand
(brand
)
self
.set_max_speed
(max_speed
)
def get_brand(self
):
return self
._brand
def set_brand(self
, brand
):
self
._brand
= brand
def get_max_speed(self
):
return self
._max_speed
def set_max_speed(self
, max_speed
):
if max_speed
< 0:
raise ValueError
('Invalid max speed for car')
self
._max_speed
= max_speed
def __str__(self
):
return 'Car: [品牌=%s, 最高时速=%d]' % (self
._brand
, self
._max_speed
)
brand
= property(get_brand
, set_brand
)
max_speed
= property(get_max_speed
, set_max_speed
)
car
= Car
('QQ', 120)
print(car
)
car
.max_speed
= 320
car
.brand
= "Benz"
print(car
)
print(Car
.brand
)
print(Car
.brand
.fget
)
print(Car
.brand
.fset
)
Car: [品牌=QQ, 最高时速=120]
Car: [品牌=Benz, 最高时速=320]
<property object at 0x03F58A50>
<function Car.get_brand at 0x03F4F468>
<function Car.set_brand at 0x03F4F3D8>
属性访问器-getter属性修改器-setter属性删除器-deleter
"""
--(2)访问器/修改器/删除器——包装器
"""
class Car(object):
__slots__
= ('_brand', '_max_speed')
def __init__(self
, brand
, max_speed
):
self
._brand
= brand
self
._max_speed
= max_speed
@
property
def brand(self
):
return self
._brand
@brand
.setter
def brand(self
, brand
):
self
._brand
= brand
@brand
.deleter
def brand(self
):
del self
._brand
@
property
def max_speed(self
):
return self
._max_speed
@max_speed
.setter
def max_speed(self
, max_speed
):
if max_speed
< 0:
raise ValueError
('Invalid max speed for car')
self
._max_speed
= max_speed
def __str__(self
):
return 'Car: [品牌=%s, 最高时速=%d]' % (self
._brand
, self
._max_speed
)
car
= Car
('QQ', 120)
print(car
)
car
.max_speed
= 320
car
.brand
= "Benz"
print(car
)
del car
.brand
print(Car
.brand
)
print(Car
.brand
.fget
)
print(Car
.brand
.fset
)
print(Car
.brand
.fdel
)
Car: [品牌=QQ, 最高时速=120]
Car: [品牌=Benz, 最高时速=320]
<property object at 0x03F5FFC0>
<function Car.brand at 0x03F4F6A8>
<function Car.brand at 0x03F4F660>
<function Car.brand at 0x03F4F858>
3. __slots__魔法
class Person(object):
__slots__
= ('_name', '_age', '_gender')
def __init__(self
, name
, age
):
self
._name
= name
self
._age
= age
@
property
def name(self
):
return self
._name
@
property
def age(self
):
return self
._age
@age
.setter
def age(self
, age
):
self
._age
= age
def play(self
):
if self
._age
<= 16:
print('%s正在玩飞行棋.' % self
._name
)
else:
print('%s正在玩斗地主.' % self
._name
)
def main():
person
= Person
('王大锤', 22)
person
.play
()
person
._gender
= '男'
person
.phone
='13000000'
if __name__
== '__main__':
main
()
王大锤正在玩斗地主.
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-38-f938be77850d> in <module>
34
35 if __name__ == '__main__':
---> 36 main()
<ipython-input-38-f938be77850d> in main()
31 person.play()
32 person._gender = '男'
---> 33 person.phone='13000000' # 此句报错,由于person定义时phone没有被放入__slots__中
34
35 if __name__ == '__main__':
AttributeError: 'Person' object has no attribute 'phone'
4. 类中的方法
4.1 实例方法
若类中定义的方法是发送给对象的消息,则是实例方法,之前实例中我们在类中定义的方法都是对象方法。
4.2 类方法
class people:
country
= "china"
@
classmethod
def getCountry(cls
):
return cls
.country
p
= people
()
print(p
.getCountry
())
print(people
.getCountry
())
china
china
class people:
country
="china"
@
classmethod
def getCountry(cls
):
return cls
.country
@
classmethod
def setCountry(cls
,country
):
cls
.country
= country
p
= people
()
print(p
.getCountry
())
print(people
.getCountry
())
p
.setCountry
("Japan")
print(p
.getCountry
())
print(people
.getCountry
())
china
china
Japan
Japan
from time
import time
, localtime
, sleep
class Clock(object):
"""数字时钟"""
def __init__(self
, hour
=0, minute
=0, second
=0):
self
._hour
= hour
self
._minute
= minute
self
._second
= second
@
classmethod
def now(cls
):
ctime
= localtime
(time
())
return cls
(ctime
.tm_hour
, ctime
.tm_min
, ctime
.tm_sec
)
def run(self
):
"""走字"""
self
._second
+= 1
if self
._second
== 60:
self
._second
= 0
self
._minute
+= 1
if self
._minute
== 60:
self
._minute
= 0
self
._hour
+= 1
if self
._hour
== 24:
self
._hour
= 0
def show(self
):
"""显示时间"""
return 'd:d:d' % \
(self
._hour
, self
._minute
, self
._second
)
def main():
clock
= Clock
.now
()
count
= 0
while True:
print(clock
.show
())
sleep
(1)
clock
.run
()
count
+= 1
if count
== 6:
break
if __name__
== '__main__':
main
()
18:39:27
18:39:28
18:39:29
18:39:30
18:39:31
18:39:32
4.3 静态方法
class people3:
country
= "china"
@
staticmethod
def getCountry():
return people3
.country
p
= people3
()
print(p
.getCountry
())
print(people3
.getCountry
())
china
china
from math
import sqrt
"""
我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长
未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不
是对象方法,这个方法是属于三角形类而并不属于三角形对象的
"""
class Triangle(object):
def __init__(self
, a
, b
, c
):
self
._a
= a
self
._b
= b
self
._c
= c
@
staticmethod
def is_valid(a
, b
, c
):
return a
+ b
> c
and b
+ c
> a
and a
+ c
> b
def perimeter(self
):
return self
._a
+ self
._b
+ self
._c
def area(self
):
half
= self
.perimeter
() / 2
return sqrt
(half
* (half
- self
._a
) * (half
- self
._b
) * (half
- self
._c
))
def main():
a
, b
, c
= 3, 4, 1
if Triangle
.is_valid
(a
, b
, c
):
t
= Triangle
(a
, b
, c
)
print(t
.perimeter
())
print(t
.area
())
else:
print('无法构成三角形.')
if __name__
== '__main__':
main
()
无法构成三角形.
4. 运算符重载
"""
运算符重载:__gt__ / __lt__
"""
class Student(object):
def __init__(self
, name
, age
):
self
._name
= name
self
._age
= age
@
property
def name(self
):
return self
._name
def study(self
, course_name
):
print('%s正在学习%s.' % (self
._name
, course_name
))
def watch_tv(self
):
if self
._age
< 18:
print('%s只能观看《熊出没》.' % self
._name
)
else:
print('%s正在观看《死神来了》.' % self
._name
)
def __gt__(self
, other
):
return self
._age
> other
._age
def __lt__(self
, other
):
return self
._age
< other
._age
if __name__
== '__main__':
stu1
= Student
('五月猴', 27)
stu1
.study
('Python程序设计')
stu1
.watch_tv
()
stu2
= Student
('王二小', 15)
stu2
.study
('思想品德')
stu2
.watch_tv
()
print(stu1
> stu2
)
print(stu1
< stu2
)
五月猴正在学习Python程序设计.
五月猴正在观看《死神来了》.
王二小正在学习思想品德.
王二小只能观看《熊出没》.
True
False
"""
运算符重载 - 自定义分数类
"""
from math
import gcd
class Rational(object):
def __init__(self
, num
, den
=1):
if den
== 0:
raise ValueError
('分母不能为0')
self
._num
= num
self
._den
= den
self
.normalize
()
def simplify(self
):
x
= abs(self
._num
)
y
= abs(self
._den
)
factor
= gcd
(x
, y
)
if factor
> 1:
self
._num
//= factor
self
._den
//= factor
return self
def normalize(self
):
if self
._den
< 0:
self
._den
= -self
._den
self
._num
= -self
._num
return self
def __add__(self
, other
):
new_num
= self
._num
* other
._den
+ other
._num
* self
._den
new_den
= self
._den
* other
._den
return Rational
(new_num
, new_den
).simplify
().normalize
()
def __sub__(self
, other
):
new_num
= self
._num
* other
._den
- other
._num
* self
._den
new_den
= self
._den
* other
._den
return Rational
(new_num
, new_den
).simplify
().normalize
()
def __mul__(self
, other
):
new_num
= self
._num
* other
._num
new_den
= self
._den
* other
._den
return Rational
(new_num
, new_den
).simplify
().normalize
()
def __truediv__(self
, other
):
new_num
= self
._num
* other
._den
new_den
= self
._den
* other
._num
return Rational
(new_num
, new_den
).simplify
().normalize
()
def __str__(self
):
if self
._num
== 0:
return '0'
elif self
._den
== 1:
return str(self
._num
)
else:
return '(%d/%d)' % (self
._num
, self
._den
)
if __name__
== '__main__':
r1
= Rational
(2, 3)
print(r1
)
r2
= Rational
(6, -8)
print(r2
)
print(r2
.simplify
())
print('%s + %s = %s' % (r1
, r2
, r1
+ r2
))
print('%s - %s = %s' % (r1
, r2
, r1
- r2
))
print('%s * %s = %s' % (r1
, r2
, r1
* r2
))
print('%s / %s = %s' % (r1
, r2
, r1
/ r2
))
(2/3)
(-6/8)
(-3/4)
(2/3) + (-3/4) = (-1/12)
(2/3) - (-3/4) = (17/12)
(2/3) * (-3/4) = (-1/2)
(2/3) / (-3/4) = (-8/9)
5. 类之间的关系
5.1 关联关系
"""
对象之间的关联关系
"""
from math
import sqrt
class Point(object):
def __init__(self
, x
=0, y
=0):
self
._x
= x
self
._y
= y
def move_to(self
, x
, y
):
self
._x
= x
self
._y
= y
def move_by(self
, dx
, dy
):
self
._x
+= dx
self
._y
+= dy
def distance_to(self
, other
):
dx
= self
._x
- other
._x
dy
= self
._y
- other
._y
return sqrt
(dx
** 2 + dy
** 2)
def __str__(self
):
return '(%s, %s)' % (str(self
._x
), str(self
._y
))
class Line(object):
def __init__(self
, start
=Point
(0, 0), end
=Point
(0, 0)):
self
._start
= start
self
._end
= end
@
property
def start(self
):
return self
._start
@start
.setter
def start(self
, start
):
self
._start
= start
@
property
def end(self
):
return self
.end
@end
.setter
def end(self
, end
):
self
._end
= end
@
property
def length(self
):
return self
._start
.distance_to
(self
._end
)
if __name__
== '__main__':
p1
= Point
(3, 5)
print(p1
)
p2
= Point
(-2, -1.5)
print(p2
)
line
= Line
(p1
, p2
)
print(line
.length
)
line
.start
.move_to
(2, 1)
line
.end
= Point
(1, 2)
print(line
.length
)
(3, 5)
(-2, -1.5)
8.200609733428363
1.4142135623730951
5.2 依赖关系
"""
对象之间的依赖关
"""
class Car(object):
def __init__(self
, brand
, max_speed
):
self
._brand
= brand
self
._max_speed
= max_speed
self
._current_speed
= 0
@
property
def brand(self
):
return self
._brand
def accelerate(self
, delta
):
self
._current_speed
+= delta
if self
._current_speed
> self
._max_speed
:
self
._current_speed
= self
._max_speed
def brake(self
):
self
._current_speed
= 0
def __str__(self
):
return '%s当前时速%d' % (self
._brand
, self
._current_speed
)
class Student(object):
def __init__(self
, name
, age
):
self
._name
= name
self
._age
= age
@
property
def name(self
):
return self
._name
def drive(self
, car
):
print('%s驾驶着%s欢快的行驶在去西天的路上' % (self
._name
, car
._brand
))
car
.accelerate
(30)
print(car
)
car
.accelerate
(50)
print(car
)
car
.accelerate
(50)
print(car
)
if __name__
== '__main__':
stu
= Student
('王小二', 15)
car
= Car
('QQ', 120)
stu
.drive
(car
)
王小二驾驶着QQ欢快的行驶在去西天的路上
QQ当前时速30
QQ当前时速80
QQ当前时速120
6. 继承
"""
(1) 继承示例
-继承的语法
-调用父类方法
-子类中定义特有的属性和方法
"""
class Person(object):
"""人(Person父类)"""
def __init__(self
, name
, age
):
self
._name
= name
self
._age
= age
@
property
def name(self
):
return self
._name
@
property
def age(self
):
return self
._age
@age
.setter
def age(self
, age
):
self
._age
= age
def play(self
):
print('%s正在愉快的玩耍.' % self
._name
)
def watch_tv(self
):
if self
._age
>= 18:
print('%s正在观看死神来了.' % self
._name
)
else:
print('%s只能观看《熊出没》.' % self
._name
)
class Student(Person
):
"""学生(子类继承Person父类)"""
def __init__(self
, name
, age
, grade
):
super().__init__
(name
, age
)
self
._grade
= grade
@
property
def grade(self
):
return self
._grade
@grade
.setter
def grade(self
, grade
):
self
._grade
= grade
def study(self
, course
):
print('%s的%s正在学习%s.' % (self
._grade
, self
._name
, course
))
class Teacher(Person
):
"""老师(子类继承Person父类)"""
def __init__(self
, name
, age
, title
):
super().__init__
(name
, age
)
self
._title
= title
@
property
def title(self
):
return self
._title
@title
.setter
def title(self
, title
):
self
._title
= title
def teach(self
, course
):
print('%s%s正在讲%s.' % (self
._name
, self
._title
, course
))
def main():
stu
= Student
('王二小', 15, '初三')
stu
.study
('数学')
stu
.watch_tv
()
t
= Teacher
('五月猴', 27, '研究僧')
t
.teach
('Python程序设计')
t
.watch_tv
()
if __name__
== '__main__':
main
()
初三的王二小正在学习数学.
王二小只能观看《熊出没》.
五月猴研究僧正在讲Python程序设计.
五月猴正在观看死神来了.
"""
(2) 多重继承
- 菱形继承(钻石继承)
- C3算法(替代DFS的算法)
"""
class A(object):
def foo(self
):
print('foo of A')
class B(A
):
"""B(子类继承A父类)"""
pass
class C(A
):
"""C(子类继承A父类)"""
def foo(self
):
print('foo fo C')
class D(B
, C
):
"""D(子类继承B,C父类)"""
pass
class E(D
):
"""E(子类继承D父类)"""
def foo(self
):
print('foo in E')
super().foo
()
super(B
, self
).foo
()
super(C
, self
).foo
()
if __name__
== '__main__':
d
= D
()
d
.foo
()
print('-'*50)
e
= E
()
e
.foo
()
foo fo C
--------------------------------------------------
foo in E
foo fo C
foo fo C
foo of A
"""
(3) 多重继承应用
- 通过多重继承可以给一个类的对象具备多方面的能力
- 这样在设计类的时候可以避免设计太多层次的复杂的继承关系
"""
class Father(object):
def __init__(self
, name
):
self
._name
= name
def gamble(self
):
print('%s在打麻将.' % self
._name
)
def eat(self
):
print('%s在大吃大喝.' % self
._name
)
class Monk(object):
def __init__(self
, name
):
self
._name
= name
def eat(self
):
print('%s在吃斋.' % self
._name
)
def chant(self
):
print('%s在念经.' % self
._name
)
class Musician(object):
def __init__(self
, name
):
self
._name
= name
def eat(self
):
print('%s在细嚼慢咽.' % self
._name
)
def play_piano(self
):
print('%s在弹钢琴.' % self
._name
)
class Son(Musician
, Father
, Monk
):
def __init__(self
, name
):
Father
.__init__
(self
, name
)
Monk
.__init__
(self
, name
)
Musician
.__init__
(self
, name
)
son
= Son
('王大锤')
son
.gamble
()
son
.eat
()
son
.chant
()
son
.play_piano
()
王大锤在打麻将.
王大锤在细嚼慢咽.
王大锤在念经.
王大锤在弹钢琴.
7. 多态
from abc
import ABCMeta
, abstractmethod
class Pet(object, metaclass
=ABCMeta
):
"""
宠物(Pet父类)
Pet被创建为一个抽象类,就是不能够创建对象的类,这种类是专门为让其他类去继承它
通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果
"""
def __init__(self
, nickname
):
self
._nickname
= nickname
@abstractmethod
def make_voice(self
):
"""发出声音(Pet父类定义原始方法)"""
pass
class Dog(Pet
):
"""狗(Dog子类继承Pet父类)"""
def make_voice(self
):
print('%s: 汪汪汪...' % self
._nickname
)
class Cat(Pet
):
"""猫(Cat子类继承Pet父类)"""
def make_voice(self
):
print('%s: 喵...喵...' % self
._nickname
)
def main():
pets
= [Dog
('旺财'), Cat
('凯蒂')]
for pet
in pets
:
pet
.make_voice
()
if __name__
== '__main__':
main
()
旺财: 汪汪汪...
凯蒂: 喵...喵...