首页 > 其他分享 >面向对象深入

面向对象深入

时间:2022-11-03 20:14:45浏览次数:41  
标签:__ name gender self 面向对象 深入 print class

目录

动静态方法

总的来说就是在类中定义的函数有多种特性。

动态方法

类中的方法,会做一些自动的操作,比如自动把对象作为第一个参数传进去。

类中直接定义函数

类中直接定义函数 这个函数默认绑定给对象 类调用有几个参数传几个 对象调用第一个参数就是对象自身

# 绑定给对象的方法
class Student:
    school_name = '清华大学'
    def func1(self):
        print(f'{self}好好学习!')

# 这种函数用于使对象产生独有的功能
# 1.对象调用
std1 = Student()
std1.func1()  # <__main__.Student object at 0x0000023663AB6670>好好学习!  # 将对象自己传入函数
# 2.类调用
Student.func1('请')  # 请好好学习!  # 需要一个参数

被@classmethod修饰的函数

有两种情况:
1.此函数被类调用时,会自动将类作为第一个参数传入其中。
2.被对象调用时,会自动将产生该对象的类作为第一个参数传入其中。
ps:cls即class的缩写,隐喻传的是类。这个函数默认绑定给类。传的全是类。

# 绑定给类的方法
class Student:
    school_name = '清华大学'
    @classmethod
    def func2(cls):
        print('我是一个类:', cls)
# 1.类调用
Student.func2()   # 我是一个类: <class '__main__.Student'>
# 2.对象调用
std2 = Student()
std2.func2()  # 我是一个类: <class '__main__.Student'>
print(Student)  # <class '__main__.Student'>

静态方法

静态方法就是在类中定义普普通通的函数,不会进行任何自动的操作。无论是类调用,还是对象调用,都要手动传参。

被@staticmethod装饰的函数

# 静态方法
class Student:
    school_name = '清华大学'
    @staticmethod
    def func3(a,b,c):
        print('静态方法',a,b,c)
# 1.类调用
Student.func3(1,2,3)  # 静态方法 1 2 3
# 2.对象调用
std2 = Student()  # 静态方法 4 5 6
std2.func3(4,5,6)

面向对象之继承

"""
面向对象三大特性
	封装 继承 多态
1.三者中继承最为核心(实操最多 体验最强)
2.封装和多态略微抽象
"""
1.继承的含义
	在现实生活中继承表示人与人之间资源的从属关系
   		eg:儿子继承父亲 干女儿继承干爹
 	在编程世界中继承表示类与类之间资源的从属关系
    	eg:类A继承类B
2.继承的目的
	在现实生活中儿子继承父亲就拥有了父亲所有资源的支配权限
 	在编程世界中类A继承类B就拥有了类B中所有的数据和方法使用权限
	为了用!获得类中所有的数据和方法的使用权限
3.继承的实操
	class Son(Father):
        pass
 	1.在定义类的时候类名后面可以加括号填写其他类名 意味着继承其他类
 	2.在python支持多继承 括号内填写多个类名彼此逗号隔开即可
    	class Son(F1, F2, F3):
         pass
	"""
	1.继承其他类的类	Son
		我们称之为子类、派生类
	2.被继承的类  Father F1 F2 F3
		我们称之为父类、基类、超类
	ps:我们最常用的就是子类和父类
	"""

实操

单继承

class Father:
    money = 666666

    def play(self):
        print('随便花')

class Son(Father):
    pass

# 1.子类
print(Son.money)  # 666666
# 2.子类产生的对象
grandson = Son()
print(grandson.money)  # 666666

# 不仅继承的类(son)能啃老 继承的类的子孙后代都可以啃老
# 类的继承可以 让对象有多个查找数据的地方

多继承

class F1:
    money = 666666
    def play(self):
        print('随便花')

class F2:
    house = 666666
    def play(self):
        print('随便住')

class F3:
    car = 666666
    def play(self):
        print('随便开')


class Son(F1, F2, F3):
    pass

print(Son.money)  # 666666
print(Son.house)  # 666666
print(Son.car)  # 666666

继承的本质

什么时候考虑用继承?
比如我们创建一个学生类和一个老师类:

class Student:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def choice_course(self):
        print(f'{self.name}正在选课')


class Teacher:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def teach_course(self):
        print(f'{self.name}正在教课')

可以发现代码中有重复的部分! 名字 年龄 性别 这是每个人都有的属性
因此我们可以创建一个'人类' 让老师和学生继承!

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


class Student(Person):

    def choice_course(self):
        print(f'{self.name}正在选课')


class Teacher(Person):
   
    def teach_course(self):
        print(f'{self.name}正在教课')

s1 = Student('工藤新一', 19 , 'male')
print(s1.choice_course())  #  工藤新一正在选课
t1 = Teacher()  # __init__() missing 3 required positional arguments: 'name', 'age', and 'gender'   # 不传参会报错


# 当调用学生类或者老师类的时候 __init__方法会自动执行
# 是因为它们继承person类 也继承了person类的__init__方法

抽象与继承

继承本质应该分为两部分
	抽象:将多个类相同的东西抽出去形成一个新的类
 	继承:将多个类继承刚刚抽取出来的新的类

	''' ps: 先抽象后继承!
	先写子类 发现 有相同的部分 再总结成父类 这个过程叫抽象 
	抽象出来了父类 就可以继承了!'''

image
image

总结

对象 :数据与功能的结合体
类(子类):多个对象相同数据和功能的结合体
父类:多个类相同数据和功能的结合体
# ps:使用继承节省代码

名字的查找顺序(重中之重)

不继承

class C1:
    name = 'alice'

    def func(self):
        print('from func')
# 1.类
print(C1.name)  # 类肯定找的自己的
# 2.对象
obj = C1()
obj.name = 'tifa'  # 这不是对象调用类的属性! 这是对象给自己创建独有的属性!
print(obj.__dict__)  # 对象的名称空间:{'name': 'tifa'}
print(obj.name)  # tifa  # 谁近找谁 对象自己有 就找自己
'''对象的名称空间有name 类的名称空间也有name
这时候会用自己的名字 自己有就不会用别人的'''
ps: 对象可以调用类中的名字(obj.func) 或者 在对象内名称空间添加、修改名字(obj.hobby = 'eat') 这样才能修改类的属性 C1.name = 'TIFA'
'''
obj.name                找名字         对象自身>>>类
obj.name = 'alice'      增/改名字      对象自身
'''

总结:

    """
    对象查找名字的顺序
        1.先从自己的名称空间中查找
        2.自己没有再去产生该对象的类中查找
        3.如果类中也没有 那么直接报错
    对象自身 >>>    产生对象的类
    """

单继承

class F1:
    name = 'cloud'
class S1(F1):
    name = 'alice'

obj = S1()
obj.__dict__['name'] = 'tifa'  # 避免混淆
print(obj.name)  # ‘tifa’
'''
    对象自身   >>>   产生对象的类     >>>    父类
'''
ps:继承的多也一样,一层一层往上找!
ps:如果所有地方都找不到会报错 报错只报产生对象的类的错!

面试题

 class A1:
        def func1(self):
            print('from A1 func1')

        def func2(self):
            print('from A1 func2')
            self.func1()

    class B1(A1):
        def func1(self):
            print('from B1 func1')

obj = B1()
obj.func2()  # 问终端的输出结果是什么?
'''
结果:
from A1 func2
from B1 func1
'''
"""
	强调:对象点名字 永远从对象自身开始一步步查找
	以后在看到self.名字的时候 一定要搞清楚self指代的是哪个对象
"""

image

整活

class A1:
    def func1(self):
        print('from A1 func1')

    def func2(self):
        print('from A1 func2')
        self.func1()


class B1(A1):
    def func1(self):
        print('from B1 func1')
        self.func2()  # 又可以递归调用了!! 


obj = B1()
obj.func2() # RecursionError: maximum recursion depth exceeded while calling a Python object

# ps:递归和循环哪个效率高???

多继承

class F1:
    name = 'miku'

class F2:
    name = 'alice'

class F3:
    name = 'cloud'

class S1(F1, F2, F3):
    pass

obj = S1()
print(obj.name)  # miku
 '''
      对象自身   >>>   产生对象的类    >>>    父类(从左往右)
 '''

非菱形继承

特点:没有形成闭环 深度优先
查找顺序:
image

菱形循环

特点:形成闭环 广度优先
查找顺序:
image

mro()方法

使用mro方法可以看到名字的查找顺序

# 非菱形循环

class A:
    # name = 'from A'
    pass


class B:
    # name = 'from B'
    pass


class C:
    # name = 'from C'
    pass


class D(A):
    # name = 'from D'
    pass


class E(B):
    # name = 'from E'
    pass


class F(C):
    # name = 'from F'
    pass


class S1(D, E, F):
    pass


obj = S1()
print(S1.mro())
'''
[<class '__main__.S1'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.E'>, <class '__main__.B'>, 
<class '__main__.F'>, <class '__main__.C'>, <class 'object'>]'''
'''
S1 -> D -> A -> E -> B -> F -> C 
object不考虑
'''
# ps:object不参与任何的操作 当object不存在 但实际每个类都继承了object类

经典类和新式类

object类包含一个类具有的基本条件,规定了类的结构,加载方式,常用函数。
python3中所有类都默认继承object类
"""
经典类:不继承object类或者其子类的类
新式类:继承object类或者其子类的类
    在python2中有经典类和新式类
    在python3中只有新式类(所有类默认都继承object)
"""
class Student(object):pass
# ps:以后我们在定义类的时候 如果没有其他明确的父类 也可能习惯写object兼容

派生方法(重要)

super() 基本使用

使用派生方法:让子类基于父类中某个方法做扩展

class Person:  # 父类
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(Person):  # 子类想扩展一个hobby属性
    def __init__(self, name, age, gender, hobby):
        super().__init__(name, age, gender)  # super的意思是子类调用父类的方法
        self.hobby = hobby

obj = Student('小潮',17 ,'female','eat')
print(obj.__dict__)  # {'name': '小潮', 'age': 17, 'gender': 'female', 'hobby': 'eat'}

# 想给student类产生的对象新增一个属性hobby
# 1. 用同名的__init__顶掉父类的双下init
# 2. 新增一个属性hobby
# 3. 使用super 在子类调用父类的方法__init__  相当于把name、age、gender三个参数传入父类 传谁谁是主人公 此时估计传student对象了 所以会给student对象添加三个属性
# 4. self.hobby = hobby 再给student对象新增一个属性

super完整写法

class Person:  
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(Person):  
    def __init__(self, name, age, gender, hobby):
        super(Student, self).__init__(name, age, gender)   # 完整写法 
        self.hobby = hobby
'''
完整写法
super(当前类名,self).父类的方法名
'''
ps:由于这样写会带来混淆 python3会直接进行省略 只用写super()即可

不用super实现需求

# 例子2
class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(Person):
    def __init__(self, name, age, gender, hobby):
        Person.__init__(self, name, age, gender)  # 不用super方法也能实现需求
        self.hobby = hobby

obj = Student('小潮',17 ,'female','eat')
print(obj.__dict__)  #  {'name': '小潮', 'age': 17, 'gender': 'female', 'hobby': 'eat'}

super更多使用

这里的super使得子类调用了父类。如果有多个父类那super调谁?
父类有super,子类的super怎么调?

super改写列表类


class my_list(list):

    def append(self, values):
        if values == 'key':
            print('无法append')
            return
        super().append(values)  # 调用父类的append

obj = my_list()
print(obj)  # []
obj.append(1)
obj.append(2)
print(obj)  # [1, 2]
obj.append('key')  # obj.append(2)

补充例子

# 1.例子
class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(Person):
    def __init__(self, name,  gender, hobby):
        super().__init__(name, gender, hobby)
        self.hobby = hobby


obj = Student('小潮',17 ,'female')
print(obj.__dict__)  # {'name': '小潮', 'age': 17, 'gender': 'female', 'hobby': 'female'}

# 为什么输出结果是这样?

标签:__,name,gender,self,面向对象,深入,print,class
From: https://www.cnblogs.com/passion2021/p/16854571.html

相关文章

  • 面向对象之继承
    面向对象之动静态方法@classmethod@staticmethod在类中的动态方法:class类名:name='倚天屠龙记'deffunc1(self):print('屠龙刀牛逼')#在类中直接定义函......
  • 面向对象中级
    目录面向对象中级动静态方法面向对象之继承的概念名字的查找顺序经典类与新式类派生方法super()方法使用注意事项面向对象中级动静态方法在类中定义的函数有多种特性''......
  • 面向对象编程二
    动静态方法1.什么是动态和静态动态就是绑定给对象的方法直接在类体代码中编写即可,对象调用会自动将对象当做第一个参数传入,类调用则有几个形参就传几个实参;静态方法就是......
  • 面向对象继承/派生
    内容概要动静态方法面向对象之继承的概念继承的本质名字的查找顺序经典类与新式类派生方法动静态方法classA1:name='牛'deffunc1(self):......
  • 面向对象2
    面向对象目录面向对象动静态方法面向对象之继承的概念面向对象之继承的本质面向对象之名字查找顺序面向对象之经典类与新式类面向对象之派生方法动静态方法面向对象之......
  • 面向对象进阶
    目录面向对象进阶今日内容概要今日内容详细动静态方法面向对象值继承的概念继承的本质名字的查找顺序经典类与新式类派生方法面向对象进阶今日内容概要动静态方法面向......
  • Python基础指面向对象:2、动静态方法
    面向对象一、动静态方法在类中定义的函数有多种特性1、直接在类中定义函数​ 再类中直接定义函数,默认绑定给对象,类调用时有几个参数就要传几个参数,对象调用时该函数......
  • 面向对象(下)
    目录面向对象(下)动静态方法面向对象之继承理论继承的本质对象查找名字的顺序(非常重要)经典类和新式类基于继承的派生方法(重要)作业面向对象(下)动静态方法在类中定义的函数有......
  • Python基础之面向对象:3、继承与派生
    面向对象一、三大特征之继承python三大特征:封装、继承、多态三者中继承最为核心,实际应用对,感受较为直观封装和多态略微抽象1、继承的概念继承的含义:​......
  • 面向对象之继承
    动静态方法面向对象之继承理论继承基本操作对象查找名字的顺序(非常重要)继承本质基于继承的派生方法(重要)动静态方法1.绑定给对象的方法#类中定义的函数有多种......