继承
单继承
有两个类,A类和B类,当我们说A类继承至B类的时候,那么A类就拥有了B类中的所有的属性和方法。
注意:继承者称为子类,被继承者称为父类。
继承的作用:
- 简化了代码,减少冗余。
- 提高了代码的健壮性。
- 提高了代码的安全性。
- 是多态的前提。
缺点:
耦合和内聚是描述类与类之间的关系的。耦合性越低,内聚性越高,代码越好。
class Person(object):
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
# 通过内部的方法,去修改私有属性
def setWeight(self, weight):
# 数据的过滤,这个其实可以更完善一些
if weight < 0:
weight = 0
self.__weight = weight
def getWeight(self):
return self.__weight
# 我们在这里定义一个子类,学生类,学生类继承自Person类
class Student(Person):
def __init__(self, name, age, weight):
# 调用父类中的__init__
super().__init__(name, age, weight)
student = Student("tom", 18, 180)
print(student.getWeight())
运行结果:
180
可以看出,Student类继承类Person类之后,就拥有了Person类的所有属性和方法
以前的版本的super
的写法是
super(Student, self).__init__(name, age, weight)
这也是最标准的写法,但是现在的python更为先进了
super().__init__(name, age, weight)
括号里面不写也可以了,解释器会自动帮我们识别
多继承
class Father(object):
def __init__(self, money):
self.money = money
def play(self):
print('play')
class Mother(object):
def __init__(self, eat):
self.eat = eat
def eatt(self):
print('eatt')
class Child(Father, Mother):
def __init__(self, money, eat):
Father.__init__(self, money)
Mother.__init__(self, eat)
c = Child(110, 'food')
c.play()
运行结果:
play
如果两个父类的方法的方法名重复了,会从左到右按照顺序调用父类的方法
按照我们的方法名来看的话,会调用Father的方法
对象属性与类属性
类属性:
class Person(object):
# 这里的属性实际上属于类属性(用类名来调用)
name = 'person'
print(Person.name)
运行结果:
person
对象属性:
class Person(object):
# 这里的属性实际上属于类属性(用类名来调用)
name = 'person'
def __init__(self, name):
pass
# 对象属性
self.name = name
print(Person.name)
a = Person('tom')
# 对象属性的优先级高于类属性
print(a.name)
print(Person.name)
运行结果:
person
tom
person
也可以动态的给对象添加对象属性:
a.age = 18
只针对于当前对象生效,对于类创建的其他对象没有作用。
删除对象中的类name属性在调用会使用到同名的类属性:
del a.name
print(a.name)
运行结果:
person
注意:以后千万不要将对象属性与类属性重名,因为对象属性会屏蔽掉类属性,但是当删除对象属性后,在使用又能使用到类属性了。
动态给实例添加属性和方法并使用__slots__
# 创建一个空类
class Person(object):
pass
a = Person()
# 动态添加属性,这体现了动态语言的特点(灵活)
a.name = 'jack'
print(a.name)
# 动态添加方法
def say(self):
print('my name is ' + self.name)
a.speak = say
a.speak(a)
# 这样添加不太好,因为哪有自己传自己的
运行结果:
jack
my name is jack
通过调用其他的一些方法
from types import MethodType
# 动态添加方法
def say(self):
print('my name is ' + self.name)
a.speak = MethodType(say, a)
a.speak()
# 这样就不需要给自己传参了
运行结果:
my name is jack
__ slots __
用于限制实例的属性的添加
打个比方,只允许给对象添加name, height, weight属性
在我们定义类的时候,定义一个特殊的属性 __slots__
,可以限制动态的添加属性。
class Person(object):
__slots__ = ("name", "age")
a = Person()
# 动态添加属性,这体现了动态语言的特点(灵活)
a.name = 'jack'
print(a.name)
a.height = 18
print(a.height)
运行结果:
jack
AttributeError: 'Person' object has no attribute 'height'
显而易见,除了我们指定的一些属性名之外,其他的属性都添加不进来
@property
怎么说呢?私有属性,我们用方法去访问很麻烦。肯定是没有通过直接用属性来取值玩的爽,所以就有了这个装饰器
属性直接对外暴露,不安全,没有数据的过滤
class Person(object):
def __init__(self, age):
self.__age = age
# 方法名为受限制的变量,去掉双下划线
@property
def age(self):
return self.__age
# 去掉下划线.setter
@age.setter
def age(self, age):
if age < 0:
age = 0
self.__age = age
p = Person(18)
p.age = 100 # 相当于调用setAge
print(p.age) # 相当于调用getAge
简单来讲,这个@property装饰器,就是把一个方法变为属性,我们不再需要通过方法来改变属性了,我们只需要直接通过属性就可以修改,可以让我们对受限制访问的属性使用语法。简单方便
运算符重载
让自定义的类生成的对象(实例)能够使用运算符进行操作
先看看简单的列子吧
class Person(object):
def __init__(self, age):
self.age = age
# 返回一个对象的描述信息
def __str__(self):
return "age = " + str(self.age)
# 制定加法的规则
def __add__(self, other):
return Person(self.age + other.age)
P1 = Person(18)
P2 = Person(20)
print(P1 + P2)
print(P1.__add__(P2))
运行结果:
age = 38
age = 38
是不是很神奇
算数运算符:
方法名 | 运算符和表达式 | 说明 |
---|---|---|
__ add __(self,other) | self + other | 加法 |
__ sub__(self,other) | self - other | 减法 |
__ mul__(self,other) | self * other | 乘法 |
__ truediv__(self,other) | self / other | 除法 |
__ mod__(self,other) | self % other | 取余 |
__ floordiv__(self,other) | self // other | 地板除 |
__ pow__(self,other) | self ** other | 求幂 |