面向对象

语言分类

  • 面向机器:抽象成机器指令,机器容易理解。代表:汇编语言
  • 面向过程:一件事情分步骤来完成,出现各种情况有解决办法一一对应,问题规模小可以步骤化、按部就班的处理。代表:C语言
  • 面向对象oop(object Oriented Programming):随着计算机解决问题的规模扩大、情况更复杂,需要很多部分协作,面向过程编程就不合适了,演变出了面向对象编程。代表:java、python等

面向对象

面向对象是一种认识世界、分析世界的方法论。将所有事物抽象为类。

  • 类class:类是抽象的概念,是所有事物的抽象,是一类事物的共同特征的集合。用计算机语言来描述类,就是属性和方法的集合
  • 对象instance、object:对象是类的具象,是一个实体(或者叫实例)。对于每个人这个个体,都是抽象概念人类的不同的实体。
  • 属性:它是对象状态的抽象,用数据结构来描述。
  • 操作:它是对象行为的抽象,用操作名和实现该操作的方法来描述。
  • Python哲学:一切皆对象;对象是数据和操作的封装;对象是独立的,但是对象之间可以相互作用。目前oop是最接近人类认知的编程范式。

面向对象三要素

  1. 封装
    • 组装:将数据和操作组装到一起
    • 隐藏数据:对外只暴露一些接口,通过接口访问对象。
  2. 继承
    • 多复用:继承来的就不用自己重新定义
    • 多继承少修改:开放封闭原则OCP(open-closed principle),使用继承来改变、体现个性
  3. 多态
    • 面向对象编程最灵活的地方,动态绑定

举例:人类就是封装;人类继承自动物类,孩子继承父母特征。分单一继承、多继承;多态,继承自动物类的人类、猫类的操作‘吃’不同。

Python的类

  • 定义
    class ClassName:
    	block
  1. 必须使用class关键字
  2. 类名必须使用大驼峰命名
  3. 类定义完成后,就产生了一个类对象,绑定到了ClassName上
  • 类对象及类属性
    • 类对象:类的定义就会生成一个类对象
    • 类的属性:类定义中的变量和类中定义的方法都是类的属性
    • 类变量:x是类MyClass的变量 MyClass中,x、foo都是类的属性,__doc__也是类的属性

    foo方法是类的属性,如同吃是人类的方法,但是每一个具体的人才能吃东西,也就是说吃是人的实例才能调用的方法。

    foo是method方法对象,不是普通的函数对象function了,他必须至少有一个参数,且第一个参数必须是self(self指代当前实例本身),这个参数位置就留给了self。

  • 实例化 a = MyClass() #实例化 使用上面的语法,在类对象后面加上一个括号,就调用类的实例化方法,完成实例化。 实例化就是真正创建一个该类的对象。 实例化后获得的实例,是不同的实例,即使是使用同样的参数实例化,也得到不一样的对象。Python类实例化后,会自动调用__init__方法。这个方法可以有多个参数,但是第一个参数必须留给self,其他没有要求。
  • __init__方法 MyClass()实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后饮食调用。作用:对实例进行初始化。 初始化函数可以多个参数,请注意第一个位置必须是self,例如init(self,name,age)

注意:__init__()方法不能有返回值,也就是只能是None

  • 实例对象instance 类实例化后一定会获得一个对象,就是实例对象 类实例化出一个实例对象,实例对象会绑定方法,调用方法时采用jerry.showage()的方式。 self.name就是jerry对象的name,name是保存在了jerry对象上,而不是Person类上。所以,称为实例变量。
  • self

    self就是调用者,就是c对应的实例对象。 self这个名字是一个惯例,可以修改,但是为了代码的可读性,不要修改。

  • 实例变量和类变量

    实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法

特殊属性含义
__name__对象名
__class__对象的类型
__dict__对象的属性的字典
__qualname__类的限定名

举例:

上面代码中看到类属性保存在类的\_\_dict\_\_中,实例属性保存在实例的\_\_dict\_\_中,如果从实例访问类的属性,就需要解除\_\_class\_\_找到所属的类。
  • 总结 是类的属性或方法也是这个类所有实例的;是实例的属性或方法,就是这个实例自己的,通过类访问不到 类变量是属于类的变量,这个类的所有实例可以共享这个变量。 实例可以动态的给自己增加一个属性。实例.__dict__[变量名]和实例.变量名都可以访问到 实力的同名变量会隐藏这类变量,或者说是覆盖了这个类变量。 实例属性的查找顺序:指的是实例使用.来访问属性,会先找自己的__dict__,如果没有会通过属性__class__找到自己的类,再去类的__dict__中找 一般来说,类变量使用全大写来命名

装饰一个类

需求:为一个类通过装饰,,增加一些类属性

之所以能够装饰,本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象。

类方法和静态方法

例子中定义的init等方法本身都是类的属性,第一个参数必须是self,erself必须只想一个对象,也就是类必须实例化后由实例来调用这个方法。 普通函数

Person.normal_method()可以调用,因为这个方法只是被Person这个名词空间管理的一个普通的方法,normal_method这是Person.normal的一个属性而已。 由于normal_method再定义是再有指定self,所以不能完成实例对象的绑定,不能用Person().normal_method()调用。 ==注意:虽然语法对,但是禁止这么写。

  • 类方法
    1. 在类定义中使用@classmethod装饰器修饰的方法
    2. 必须有至少一个参数,且第一个参数留给cls,cls指代调用者即类对象自身
    3. cls这个标识符可以是任意合法名称,为了代码可读性,禁止修改
    4. 通过cls可以直接操作类属性 类似于java、c++中的静态方法
  • 静态方法
    1. 在类定义中使用@staticmethod装饰器修饰的方法
    2. 调用时,不会隐式的传入参数。静态方法,只是表明这个方法属于这个名词空间。函数归在一起,方便组织管理。
  • 方法的调用
    class Person:
    	def normal_method():
    		print('normal')
    
    def method(self):
    	print("{}'s method",format(self))
    		
    @classmethod
    def classmtd(cls):
    	print('class = {0.__name__} ({0})'.format(cls))
    	cls.HEIGHT = 170
    		
    @staticmethod
    def static_methd():
    	print(Person.HEIGHT)

总结: 类除了普通方法都可以调用,普通方法需要对象的实例作为第一参数。 实例可以调用所有类中定义的方法(包括类方法、静态方法),普通方法传入实例自身,静态方法和类方法需要找到实例的类。

访问控制

  • 私有(Private)属性 私有属性:使用双下划线开头的属性名,就是私有属性 私有变量的本质:类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称**_类名__变量名**的名称,所有原来的名字访问不到了。但是如果知道了私有变量的新名称,还是可以直接从外部访问到并修改它。
  • 保护变量 在变量名前使用一个下划线,称为保护变量。保护变量和普通的属性一样,解释器不做任何特殊处理。这个只是开发者的约定,看到这种变量就知道这是保护变量,仅限于内部使用,不要直接使用。
  • 私有方法 参照保护变量、私有变量,使用单下划线、双下划线命名方法。
class Person:
	def __init__(self,name,age=18):
		self.name = name
		self.__age = age
	
	def _getname(self):
		return self.name
	
	def __getage(self):
		return self._age

tom = Person('Tom')
print(tom._getname())
print(tom.__getage())
print(tom.__Dict__)
print(tom.__class__.__dict__)
print(tom._Person__getage())

私有方法的本质:单下划线的方法只是开发者之间的约定,解释器不做任何改变。双下划线的方法是私有方法,解释器会帮助我们改名以达到隐藏该方法的目的,改名策略和私有变量相同,方法变量都在类的字典中可以找到。

  • 私有成员总结 在Python中,使用单下划线或者双下划线来标识一个成员被保护或者被私有化隐藏起来。但是,不管使用什么养的访问控制,都不能真正的阻止修改类的成员。Python中没有绝对的安全的保护成员或者私有成员。因此,签到的下划线只是一种警告和提醒,除非真有必要,否则不要修改或使用它们。

补丁

  • 可以通过修改或者替换类的成员。使用者调用方式不变,但是类提供的功能可能已经改变了。
  • 猴子补丁(MonkeyPatch):在运行时,对属性进行动态替换。慎用

属性装饰器

一般的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter读取属性和setter方法设置属性。

  • 通过age和set_age的方法操作属性
    class Person:
        def __init__(self,name,age=18):
            self.name = name
            self.__age = age
    
        def age(self):
            return self.__age
    
        def set_age(self,age):
            self.__age = age
    
    jerry = Person('jerry')
    print(jerry.age())
    jerry.set_age(24)
    print(jerry.age())
  • 使用属性装饰器的简单方法
    class Person:
        def __init__(self,name,age=18):
            self.name = name
            self.__age = age
    
        @property
        def age(self):
            return self.__age
        
        @age.setter
        def age(self,age):
            self.__age = age
    
        @age.deleter
        def age(self):
            del self.__age
            print('delete completed')
    
    jerry = Person('jerry')
    print(jerry.age)
    jerry.age = 24
    print(jerry.age)
    del jerry.age
  • Property装饰能通过简单的方式把对方法的操作变成对属性的访问,并起到了隐藏效果。特别注意:以下三个方法同名,但是property装饰器必须在setter和deleter之前。
    1. property装饰器,后面跟的函数名就是以后的属性名。它就是getter,这个必须有,有了它至少是只读属性。
    2. setter装饰器,于属性名同名,且接收两个参数,第一个shiself,第二个是将要赋值的值。有了它,属性可写。
    3. deleter装饰器,可以控制是否删除属性。很少用

对象的销毁

类中可以定义__del__方法,称为析构函数(方法)。作用是销毁类的实例,释放占用的资源。由于Python实现了垃圾回收机制,这个方法不确定和实质性,有必要时请使用del语句删除实例,来手动调用这个方法

class person:
    def __init__(self,name,age=18):
        self.name = name
        self.age = age
        
    def __del__(self):
        print('{} is already deleted'.format(self.name))

tom = person('tom')
del tom

方法重载

在其他面向对象的高级语言中都有重载的概念。重载就是同一个方法名,但是参数数量、类型不一样。但是Python中没有重载,也不需要。因为Python中,方法定义中形参非常灵活,不需要指定类型,参数个数也不固定。一个函数的定义可以实现很多种不同形式是惨的调用。

封装(Encapsulation) 面向对象三要素之一

封装就是将数据和操作组织到类中;将数据隐藏起来,该使用者提供操作。使用这通过操作可以获取或者修改数据;通过访问内控制,保留适当的数据和操作给用户,该隐藏的隐藏。

练习

  • 随机整数生成类,可以指定一批生成的个数,可以指定熟知的范围,可以调整每批生成数字的个数
from collections import namedtuple
import random

class RandNum:
    def __init__(self,pos=0,endpos=100,maxnum=20):
        self.pos = pos
        self.endpos = endpos
        self.maxnum = maxnum
        self.gen = self._gen()

    def _gen(self):
        while True:
            yield [random.randint(self.pos,self.endpos) for _ in range(self.maxnum)]

    def generate(self,count=None):
        if count == None:
            pass
        else:
            self.maxnum = count
        return next(self.gen)



rg =RandNum()
print(rg)
  • 使用上题中的类,随机生成20个数字,两两配对形成二位坐标,把坐标组织起来输出。
class CoordinatePoint:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Point({},{})'.format(self.x,self.y)

p=zip(rg.generate(),rg.generate())
print([CoordinatePoint(*item) for item in p])
  • 记录车的品牌、颜色、价格、速度等特征,并实线增加车辆信息,显示全部车辆信息的功能
class CarInfo:
    def __init__(self,mark,color,price,speed):
        self.mark = mark
        self.color = color
        self.price = price
        self.speed = speed

    def add_info(self,name,info):
        self.name = info

    def __repr__(self):
        return 'mark:{},color:{},${}w,{}Km/h'.format(self.mark,self.color,self.price,self.speed)

class Carset:
    def __init__(self):
        self.lst = []

    def add_carinfo(self,car:CarInfo):
        self.lst.append(car)

    def getall(self):
        print(self.lst)

lykan = CarInfo('Motor','blue',340,420)
carinfo = Carset()
carinfo.add_carinfo(lykan)
carinfo.getall()
  • 实现温度的处理,转换
    class Temperature:
        def __init__(self,t,unit = 'c'):
            self._c = None
            self._f = None
            self._k = None
    
            if unit == 'k':
                self._c = self.k2c(t)
                self._k = t
    
            elif unit == 'f':
                self._c = self.f2c(t)
                self._f = t
            else:
                self._c = t
    
        def __repr__(self):
            # return '摄氏度:{},华氏度:{},开氏度:{} K'.format(self._c,self._f,self._k)
            if self._c:
                return '摄氏度:{}'.format(self._c)
            elif self._f:
                return '华氏度:{}'.format(self._f)
            elif self._k:
                return '开氏度:{} K'.format(self._k)
    
        @property
        def k(self):
            if self._k is None:
                self._k = self.c2k(self._c)
            return '开氏度:{} K'.format(self._k)
        @property
        def c(self):
            if self._c is None:
                self._c = self.k2c(self._k)
            return '摄氏度:{}'.format(self._c)
        @property
        def f(self):
            if self._f is None:
                self._f = self.c2f(self._c)
            return '华氏度:{}'.format(self._f)
    
        @classmethod
        def c2f(cls,c):
            return c*9/5+32
    
        @classmethod
        def c2k(cls,c):
            return c+273.15
    
        @classmethod
        def f2c(cls,f):
            return (f-32)*5/9
    
        @classmethod
        def k2c(cls,k):
            return k - 273.15
    
        @classmethod
        def k2f(cls,k):
            return cls.c2f(cls.k2c(k))
    
        @classmethod
        def f2k(cls,f):
            return cls.c2k(cls.f2c(f))
    
    print(Temperature.c2f(40))
    print(Temperature.f2c(333.15))
    print(Temperature.c2k(40))
    print(Temperature.f2k(333.15))
    print(Temperature.k2f(190))
    print(Temperature.k2c(190))
    
    t= Temperature(120,'f')
    print(t)
    print(t.c,t.f,t.k)
  • 模拟购物车功能
    class merchandise:
        def __init__(self,name,price,count):
            self.name = name
            self.price = price
            self.count = count
        def __repr__(self):
            return 'name:{},${},count{}'.format(self.name,self.price,self.count)
    
    class ShopCar:
        def __init__(self):
            self.lst = []
    
        def add_merchandise(self,thing:merchandise):
            self.lst.append(thing)
    
        def getall(self):
            return self.lst
    
    myshopcar = ShopCar()
    
    myphone = merchandise('glaxy',5398,10)
    mycar = merchandise('maserati Granti',248,1)
    
    myshopcar.add_merchandise(mycar)
    myshopcar.add_merchandise(myphone)
    
    myshopcar.getall()

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/88382

(0)
上一篇 2017-11-13 20:18
下一篇 2017-11-13 21:53

相关推荐

  • 性能调优概述

    大纲: 一、概述 二、什么是性能调优?(what) 三、为什么需要性能调优?(why) 四、什么时候需要性能调优?(when) 五、什么地方需要性能调优?(where) 六、什么人来进行性能调优?(who) 七、怎么样进行性能调优?(How) 八、总结 注,硬件配置:CUP Xeon E5620 x 2 8核心, 内存 16G , 硬盘 RAID 10,操作…

    Linux干货 2015-02-10
  • liunx性能监控工具总结

    1.uptime 1)显示的信息:显示当前时间,系统已启动的时间,当前在线人数,系统平均负载(1分钟、5分钟、10分钟的平均负载,一般不会超过1) 2)系统平均负载:指在特定时间间隔内运行队列中的平均进程数。 3)如果每个CPU内核的当前活动进程数不大于3的话,那么系统的性能良好。如果每个CPU内核的任务数大于5,那么这台及其的性能有严重问题 4)ruguo…

    Linux干货 2016-09-09
  • Linux Bash Shell练习

    Linux Bash Shell练习 1、写一个脚本,完成以下功能: 假设某目录(/etc/rc.d/rc3.d/)下分别有K开头的文件和S开头的文件若干 显示所有以K开头的文件的文件名,并且给其附加一个stop字符串 显示所有以S开头的文件的文件名,并且给其附加一个start字符串 分别统计S开头和K开头的文件各有多少 #!/bin/bash # for&…

    Linux干货 2016-12-17
  • awk的详细用法

    awk简介 awk是一种编程语言,也可以说是一个脚本语言解释器,主要是用来实现文本的格式化输出。awk是取了其三位作者名字的首字母,即Aho,Weinberger和Kernighan。awk在Linux上是基于GNU协议实现的,即GNU awk,也就是gawk。 awk的工作模式 遍历整个文件,从第一行到最后一行。每次仅读取文件的一行,依照用户指定的输入分隔…

    Linux干货 2016-11-14
  • 用户 组

    用户 组    在linux系统中,用户管理是基于用户名和密码的方式进行资源的分配,linux上用户Username/UID分为以下类别:    管理员: root,0    普通用户: 1-65535 普通用户分为:系统用户和登录用户两种 系统用户:1-499(cen…

    系统运维 2016-08-04
  • grub详解

    #GRUB详解 grub基础概念 前面的开机过程我们知道:按照BIOS定义的硬件设备启动顺序,第一启动设备中的MBR去读取boot loader。boot loader功能很强大,要重新自检硬件设备,开始有一个菜单供用户选择系统或者内核版本,还要加载内核将内核解压到RAM中并执行,最后将控制权移交给内核。屈屈446个字节怎么让它完成那么多功能。所以Linux…

    Linux干货 2016-11-25