# Python学习笔记 Day9

面向对象进阶

Python学习笔记 Day9

面向对象进阶

这一章感觉要看好几天,两天了才把装饰器的语法结构搞清楚(我好菜啊)。

装饰器

封装和装饰器的意义:今天花了很长时间来搞懂getterssetters的意义……

Python
class Person:
    def __init__(self,age):
        self._age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        if age > 17:
            self._age = age - 17
        else:
            self._age = age

if __name__ == "__main__":
    person = Person(12)
    print(person.age)
    person.age = 18
    print(person.age)

作为对比:

Python
class Person:
    def __init__(self,age):
        self._age = age

    
    def get_age(self):
        return self._age

    def set_age(self, age):
        if age > 17:
            self._age = age - 17
        else:
            self._age = age

if __name__ == "__main__":
    person = Person(12)
    print(person.get_age())
    person.set_age(18)
    print(person._age)

前面是装饰器,后面是普通的 getter setter

那么装饰器到底有什么用呢,说好理解也好理解,就是给这个函数传了一件外衣,并没有影响到函数的性能。 至于语法糖到底有什么用,现在的我说不清楚,所以就摘抄一下:

函数不需要做任何修改,只需在定义的地方加上装饰器,调用的时候还是和以前一样,如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。 附一下原文,以供今后深入理解理解 Python 装饰器 这个部分,可能在今后的开发过程中才能深刻理解吧。

为了方便理解,我们将age给分成了不一样的字母。

Python
class Person:
    def __init__(self,a):
        self.b = a

    @property
    def c(self):
        return self.b

    @c.setter
    def c(self, a ):
        if a > 17:
            self.b = a - 17
        else:
            self.b = a

if __name__ == "__main__":
    person = Person(18)
    print(person.c)
    person.c = 18
    print(person.c)

a是形参,用来代表创造对象时,传递给对象这个属性的值。 b是对象中这个属性的名字。 c是对象方法,可以和a重名,但是不可以和属性的名字重名,不然return的时候会出现递归错误(一个类中不能有重复的名字)。准确来说,因为@property9 (getter)的存在,他其实算是对象的一个属性了。所以下文使用setter函数的时候必须保证函数名一致,保证是在给这个属性添加值。

Python
 @property
    def b(self):
        return self.b
    # RecursionError: maximum recursion depth exceeded

此外,可以看到的是,上文的代码,第一个 print 中的 setter 并没有起效,这是为什么呢,因为我们在

Python
class Person:
    def __init__(self,a):
        self.b = a

的时候,把a的值赋给了b这个属性,@property成功返回了b的属性值,但是setter无法直接处理c属性的数据,所以最后并没有经过setter处理。正确的做法是给c属性赋值,b其实c是的内部存储,是负责保存c数据的地方,所以给c属性赋值就能把b属性的值也改变,也不会影响到setter的调用。

理解好abc,对正确理解面向对象的变成意义重大。

__slots__

因为markdown里__slots__中的_如果不加上\转义的话,会起到把后文变成斜体的效果,所以使用了\进行转义处理。

__slots__起到的效果是对类的属性进行绑定,且只对当前类起效。

静态方法和类方法

  • 静态方法:可以认为是公用的方法,非这个对象专用的方法,在调用这个方法的时候,对象甚至创造出来。
  • 类方法:和静态方法比较类似,不过相当于是类当做了之前的对象。通过这个手段我们可以获取和类相关的信息并且可以创建出类的对象。在使用中需要注意的是,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象。

类之间的关系

  • is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
  • has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
  • use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。

继承和多态

多态

super() 函数是用于调用父类(超类)的一个方法。

super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

语法:super(type[, object-or-type])

@abstractmethod

Python
 from abc import ABCMeta, abstractmethod
    ...
    @abstractmethod
    def make_voice(self):
        """发出声音"""
        pass

说句题外话,这我才感觉到这比供着蛐蛐祈祷的满篇if好了有多少。

最后编辑于
文章链接: http://pheustal.com/2019/09-11/python_day9
本作品采用CC-BY-SA许可。