python面向对象(2)
动态方法和静态方法
# 动态方法
1.绑定给对象的方法
class Student:
def run(self):
print(self)
# 类调用绑定给对象的方法:有几个参数就需要传几个参数
Student.run(123)
# 对象调用绑定给对象的方法:会自动将对象当做第一个参数传入
obj1.run()
2.绑定给类的方法
class Student:
@classmethod
def eat(cls):
pr(cls)
# 类调用绑定给类的方法:会自动将类当做第一个参数传入
print(Student) # <class '__main__.Student'>
Student.eat() # <class '__main__.Student'>
# 对象调用绑定给类的方法:也不需要传参 会将产生该对象的类自动当做第一个参数传入
obj1.eat() # <class '__main__.Student'>
'''在类定义中,使用@classmethod装饰器修饰的方法,必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
cls这个标识符可以是任意合法名称,但是为了易读,请不要修改
通过cls可以直接操作类的属性'''
# 动态方法
class Student:
@staticmethod
def speak(cls):
print(cls)
1.普普通通的函数:无论谁来调 都必须传固定的参数个数
# 类调用静态方法:要自己传值
Student.speak(123)
# 对象调用静态方法:要自己传值
obj1.speak(321)
面向对象的三大特性之一:继承
# 继承的概念:
子类 拥有 父类 的所有 方法 和 属性
# 继承的基本使用
"""
class A(B):
pass
我们将被继承的类称为:父类或者基类 B
继承别人的类称为:子类或者派生类 A
"""
# 在python中一个类可以同时继承多个父类
class A(B,C,D):
pass
子类 继承自父类,可以直接享受 父类中已经封装好的方法,不需要再次开发
子类 中应该根据 职责,封装 子类特有的属性和方法
继承的本质
抽象:由下往上抽取相同特征
继承:由上往下直接白嫖资源
"""
在面向对象编程中 其实类和父类的主要功能都是用来减少代码冗余的
对象:数据与功能的结合体
类:多个对象相同数据和功能的结合体
父类:多个类相同数据和功能的结合体
"""
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(Person):
def teach(self):
print(f'{self.name}老师正在讲课')
class Student(Person):
def study(self):
print(f'{self.name}学生正在学习')
stu1 = Student('jason', 18, 'male')
#总结
class Student(Person)这种形式就是从父类继承,括号中写上继承的类的列表。
继承可以让子类从父类获取特征(属性和方法)
父类:
calss Person就是Student和Teacher的父类,也称为基类,超类
子类:
Student就是Person的子类,也成为派生类
#在Python3中,object类是所有对象的根基类
class A:
pass
'如果类定义时,没有基类列表,等同于继承自object'
class A(object):
pass
新式类和经典类
#新式类:
以 object 为基类的类,推荐使用
#经典类:
不以 object 为基类的类,不推荐使用
Python 3.x
定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类
Python 2.x
定义类时,如果没有指定父类,则不会以 object 作为 基类
'''为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行!
今后在定义类时为了兼容,如果没有父类,建议统一继承自 object '''
查看继承的特殊属性和方法
class A:
pass
print(A.__base__) #类的基类。
print(A.__bases__) #类的基类元组。
print(A.__mro__) #显示方法查找顺序,基类的元组。
print(A.mro()) #同上,返回列表。
print(A.__subclasses__()) #类的子类列表。
继承的优缺点
#继承的特点:
a.子类的独享可以直接访问父类中未被私有化的属性,访问私有化属性时,需要在父类提供get和set方法
b.子类对象可以调用父类中未被私有化的方法
c.父类对象无法访问子类对象的属性和方法
#优缺点:
1.优点:
可以简化代码,减少冗余
可以提高代码的维护性
可以提高代码的安全性
继承是多态的前提
2.缺点:
耦合和内聚被用来描述类与类之间的关系,一般高内聚低耦合说明代码比较好
继承关系中耦合性相对较高【如果修改父类,则所有子类需求都会改变】
名字的查找顺序
不继承情况下
# 名字的查找顺序是
先从对象自己的名称空间中查找 没有则去类里面的名称空间查找
对象 >>> 类
'''注意设置值的情况下是在自身的名称空间中添加或者修改数据'''
单继承情况下
#名字的查找顺序是
先从对象自己的名称空间中查找 没有择取产生对象的类中查找
如果还没有并且类有父类则去父类中查找 以此往复下去!!!
对象 >>> 类 >>> 父类
# 代码示例:
class A:
def f1(self):
print('from A.f1')
def f2(self):
print('from A.f2')
self.f1() '''以后看到self点东西 一定要问自己self是谁'''
class MyClass(A):
def f1(self):
print('from MyClass.f1')
obj = MyClass()
obj.f2()
# 执行的方法分别是A里面的f2和MyClass里面的f1
#查询顺序
1.对象.属性 : 先从对象空间找,再从类名空间找,再从父类找
2.类名.属性 : 先从类名空间找,再从父类找
3.对象与对象之间是相互独立的
多继承情况下(了解)
'研究菱形和非菱形问题object不参与图形构建'
#非菱形继承的情况下
父类中名字的查找顺序就是按照继承时从左往右依次查找
如果多个父类还有分类 那么遵循"深度优先"
eg:D->C->B->A
#菱形继承的情况下
父类中名字的查找顺序就是按照继承时从左往右依次查找
如果多个父类还有分类 那么遵循"广度优先"
D->B->C->A

派生类
# 派生的定义:
子类可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)
重新定义了自己的属性且与父类重名那么调用新增的属性时 就以自己为准
#代码示例:
class Animal():
def __init__(self,name,age,gender,birth):
self.name = name
self.age = age
self.gender = gender
self.birth = birth
class Cat(Animal):
def __init__(self,name,age,gender,birth,eat,live):
# 子类调用父类的方法
super().__init__(name,age,gender,birth)
# 自己还要添加一个额外的东西
self.eat = eat
self.live = live
class Dog(Animal):
def __init__(self,name,age,gender,birth,play,sleep):
super().__init__(name,age,gender,birth)
self.play = play
self.sleep = sleep
"""
如果自己写的子类需要使用父类的方法 并且还需要基于该方法做扩展
这样的子类我们称之为派生类(本质还是子类)
那么可以使用super关键字来实现
"""
