当前位置: 首页 > 科技观察

Python关于面向对象的六大问题

时间:2023-03-12 02:16:31 科技观察

这篇文章是为刚接触Python的朋友写的,试图解释以下几个问题:什么是类和对象?既然有了函数,为什么还需要类呢?Python是如何定义public/protected/Private属性/方法的?私有真的是私有的吗?这样做的目的是什么?类函数、成员函数、静态函数如何定义?只能使用类的函数,否则抛出异常?有如下继承关系:A,B(A),C(A),D(B,C)那么在初始化D的时候,A,B,C的初始化顺序是怎么样的呢?A会被初始化两次吗?1.什么是类和对象?先说对象吧。对象通常有两个含义。它们指的是作为行动或思想目标的事物,或专指恋爱中的另一方。在编程的世界里,对象就是存在于客观世界中的人、物、物等实体在计算机逻辑中的映射。在编程的时候,你可以把对象映射到任何你想要的东西,但是如果映射更常规,代码更容易使用和理解,更有利于后续的快速迭代和扩展。在Python世界中,一切都是对象。再来说说类,类就是分类的类,代表相似事物的集合,对应Python关键字class。对象是类中的具体事物,在类初始化后产生,通常称为对象,或实体。比如女人是一个类,你女朋友是一个对象。属性:对象的一种静态特征,比如你女朋友的肤色、种族、血型等功能:对象的某种动态能力,比如你女朋友会唱歌、会弹钢琴等。虽然给出的例子可能不合适,希望加深大家的理解。其实更准确的定义是:类是具有相同属性和功能的对象的集合。2、既然有了函数,为什么还需要类?函数是为了解决代码复用,但是函数是过程思维,太具体了,太具体的东西会有很多重复,所以我们需要把问题抽象出来,而类就是抽象的,抽象的类,更可复用,更容易面对复杂的业务逻辑,也减轻了程序员编程时的内存压力。如果没有class,我们就更容易把代码写成一堆屎,牵一发而动全身,不敢修改。有了类,我们就更容易编写易读、易维护、易扩展的代码。3.Python如何定义public/protected/private属性/方法?privateyes和no是真正的私有。这样做的目的是什么?Python约定protected/private属性/方法的形式如下:__表示private_表示protectedexcept前两个是public的所谓约定,即当你看到以双下划线或单下划线开头的变量或方法时,你应该有意识地不要在课堂外修改或访问它。也就是说,Python不会阻止程序员访问该类。私有属性还是私有方法,Python选择信任程序员。访问公共属性和访问受保护属性之间没有区别。如果你想访问私有属性,你需要这个:object._ClassName__PrivateMember4。类函数、成员函数、静态函数如何定义,它们的作用是什么?看注释:classDocument():WELCOME_STR='Welcome!这本书的上下文是{}。def__init__(self,title,author,context):print('调用了__init__函数')self.title=titleself.author=authorself.__context=context#classfunction@classmethoddefcreate_empty_book(cls,title,author):returncls(title=title,author=author,context='nothing')#成员函数defget_context_length(self):returnlen(self.__context)#staticFunction@staticmethoddefget_welcome(context):returnDocument.WELCOME_STR.format(context)empty_book=Document.create_empty_book('除了性,每个人都在想什么','SheridanSimove教授')print(empty_book.get_context_length())print(empty_book.get_welcome('确实没什么'))类函数用@classmethod修饰,第一个参数必须是cls,代表类本身,也就是说我们可以在classmethod函数中调用类的构造函数cls(),从而生成一个新的实例从这一点我们可以推断出它的使用场景:当我们需要再次调用构造函数时,即创建一个新的实例对象时,我们需要在不修改现有实例的情况下返回一个新的实例。成员函数很常见,是一个对象可以直接调用的方法,第一个参数必须是self。静态函数,用@staticmethod修饰,通常表示这个函数的计算不涉及类的变量,不需要类的实例化就可以使用,也就是说函数和这个类的关系是不是很近。也就是说,也可以在类外定义使用staticmethod修饰的Functions。有时候会想是在类中使用staticmethod还是在utils.py中单独写一个函数。5.类可以继承。如何让子类必须重写父类的函数才能使用,否则会抛出异常?有两种方法,推荐第二种。第一种:classA:deffun(self):raiseException("notimplement")classB(A):passb=B()b.fun()第二种:fromabcimportABCMeta,abstractmethodclassA(metaclass=ABCMeta):@abstractmethoddeffun(self):passclassB(A):passb=B()b.fun()6.有如下继承关系:A,B(A),C(A),D(B,C)那么在初始化D的时候,A、B、C的初始化顺序是怎样的呢?A会被初始化两次吗?--->B---A--->D--->C---A、B、C的初始化顺序是什么?不妨自己写代码看看。有两种方式,第一种会初始化A两次,第二种不会。第一个:A类:def__init__(self):print("Aiscalled")classB(A):def__init__(self):print("Biscalled")A.__init__(self)classC(A):def__init__(self):print("Ciscalled")A.__init__(self)classD(B,C):def__init__(self):print("Discalled")B.__init__(self)C.__init__(self)d=D()输出:D被调用B被调用A被调用C被调用A被调用第二种类型:classA:def__init__(self):print("enterA")print("levaveA")B类(A):def__init__(self):print("enterB")super().__init__()print("levaveB")C类(A):def__init__(self):print("输入C")super().__init__()print("levaveC")classD(B,C):def__init__(self):print("enterD")super().__init__()print("levaveD")d=D()输出;enterDenterBenterCenterAlevaveAlevaveClevaveClevaveBlevaveD第一种方法很清楚菱形继承的潜在问题:一个基类初始化函数可能会被调用两次。在通用工程中,这显然不是我们想要的。正确的做法应该是使用super来调用父类的构造函数,而python使用了一种叫做方法解析顺序的算法(具体实现算法叫做C3)来保证一个类只会被初始化一次。也就是说,能用super就用super。