python 基础四(面向对象)

面向对象

面向对象

  • 与面向过程对比
    • 面向过程:数学逻辑的映射,学会做个好员工
    • 面向对象:生活逻辑的映射,学会做个好领导
  • 生活实例
    • 类: 人 手机 电脑
    • 对象: 小明、老王 你的手机、我的手机 我的电脑、你的电脑
  • 官方定义
    • 类:具有相同特征(属性和行为)事物的抽象
    • 对象:某个类的具象
  • 编程语言
    • 类:是一种自定义的数据类型
    • 对象:某个类类型的变量

基础语法

  • 类的定义
    class 类名:
    pass

  • 使用说明:

    • 定义类的关键字是class

    • 类名:原则上符合标识符命名规范即可,但是通常都采用大驼峰风格命名,如:UserName

    • 类名后不要忘记’:’

    • 类的内容要进行整体缩进

    • 属性可以通过变量体现,行为通过函数体现

    • 成员访问:

      • 属性:对象.属性名
      • 方法:对象.方法名()
    • 示例:

      定义类

      class Person:
      # 行为通过函数体现

        # 吃饭
        def eat(self):
            print('毛氏红烧肉,听说很好吃!')
      
        # 睡觉
        def sleep(self):
            print('喜欢睡觉也是生活态度!')
         # 创建对象  
         p = Person()
         # print(p)
        # 属性可以动态添加
        p.name = 'ergou'
        p.age = 22
        print(p.name, p.age)
         # 调用成员方法
          p.eat()
          p.sleep()
      
  • self使用
    class Person:
    def run(self):
    # self表示当前对象,就是调用该方法的对象
    print(’{}每天以2m/s的速度奔跑5km’.format(self.name))

  • __str__方法
    class Person:
    # 打印对象时默认打印:类名+地址
    # 重写该方法,打印对象时会打印该方法的返回值
    # 该方法必须返回一个字符串
    # 使用str方法强制类型转换时也会调用该方法
    def str(self):
    return ‘我是{},今年{}岁’.format(self.name, self.age)

    p = Person()
    p.name = '勒布朗.詹姆斯'
    p.age = 34
    print(p)
    
    s = str(p)
    print(s)
    
  • __init__方法
    class Cat:
    def str(self):
    return ‘name:{},age:{},color:{}’.format(self.name, self.age, self.color)

          # 构造方法:创建对象后会自动调用,可以进行初始化设置
          def __init__(self, name, age, color):
              # print('__init__')
              self.name = name
              self.age = age
              self.color = color
            
    # 这种方式比较繁琐
    # jiafei = Cat()
    # jiafei.name = '加菲'
    # jiafei.age = 2
    # jiafei.color = '橘黄色'
    # print(jiafei)
    
    jiafei = Cat('加菲', 2, '橘黄色')
    print(jiafei)         
    
  • __del__方法
    class Pig:
    # 析构方法:当对象释放时,系统会自动调用
    # 该方法一般做资源释放操作,如:断开数据库连接、文件关闭
    def del(self):
    print(‘大师兄,我不行了’)

    bajie = Pig()
    del bajie
    print('八戒,一路走好!')         
    
  • 思考:小明手里有两张牌,左手♥K,右手♠A,小明交换两手的牌后,手里分别是什么?

    • 先找到对象:♥K、♠A、左手、右手、小明
    • 根据对象抽象类:人、手、牌
    • 设计相关的类,需要根据功能反复完善

常用内置函数

  • 内置函数:在类中,特定的时刻会自动触发的函数

  • initdelstr

  • setattrgetattrdelattr
    class Person:
    def init(self, name):
    self.name = name
    # print(‘初始化对象’)

        # 当设置属性时会自动调用
        def __setattr__(self, key, value):
            # print(key, value)
            self.__dict__[key] = value
    
        # 当获取不存在的属性时会自动触发
        def __getattr__(self, item):
            if item == 'age':
                return 18
            else:
                return '你猜'
    
        # 销毁对象的指定属性时会自动触发
        def __delattr__(self, item):
            print(item, '属性即将销毁')
            
            
    xiaoming = Person('小明')
    # xiaoming.name = '小明'
    
    print(xiaoming.age)
    print(xiaoming.height)
    
    print(xiaoming.__dict__)
    
    del xiaoming.name
    print('over')
    
  • setitemgetitemdelitem
    class Person:
    # 将对象当做字典操作,添加或设置属性时自动触发
    def setitem(self, key, value):
    # print(key, value)
    self.dict[key] = value

          # 将对象当做字典操作,根据键获取值时会自动触发
          def __getitem__(self, item):
              # print(item)
              return self.__dict__.get(item)
    
          # 将对象当做字典操作,根据键销毁属性时会自动触发
          def __delitem__(self, key):
              print(key, '属性即将销毁')
              del self.__dict__[key]
                
    xiaoming = Person()
    # xiaoming.name = '小明'
    # print(xiaoming.name)
    
    xiaoming['name'] = '小明'
    print(xiaoming['name'])
    
    del xiaoming['name']
    print(xiaoming['name'])            
    
  • call
    class Person:
    # 将对象当做函数调用,该方法会自动触发
    def call(self, *args, **kwargs):
    # print(‘call’, args)
    return sum(args)

    p = Person()
    # 将对象当做函数调用,必须重写类的call方法
    ret = p(1, 2, 3)
    print(ret)
    
    def test():
    	pass
    
    # 判断一个对象是否可以调用
    print(callable(p))
    print(callable(test))
    
    # 判断一个对象是否是函数
    from inspect import isfunction
    print(isfunction(p))
    print(isfunction(test))
    
    # 判断对象是否拥有指定属性,若对象可以调用,那么一定拥有__call__属性
    print(hasattr(p, '__call__'))
    print(hasattr(test, '__call__'))
    

面向对象

面向对象三大特点

  • 封装:既是对数据结构的封装,又是处理数据的方法的封装。
  • 继承:强调的是父子类的关系
  • 多态:不同对象调用相同的方法,有不同的响应。

类的继承

  • 相关概念

    • 继承:父类的属性和方法,子类可以直接拥有,称为继承。
    • 派生:子类在父类的基础上衍生出新的特征(属性或行为),称为派生。
    • 总结:其实他们是一回事,知识描述问题的角度不同(继承侧重相同点,派生侧重不同点)
  • 继承语法
    # class Animal:
    # 当没有写父类时,默认继承自object
    class Animal(object):
    def init(self, name):
    self.name = name

        def run(self):
            print('小动物喜欢一天到晚跑个不停')
            
    # 定义一个子类,继承自Animal  
    class Dog(Animal):
        pass
    
    d = Dog('旺财')
    # 可以直接拥有父类的属性
    print(d.name)
    # 也拥有父类的行为
    d.run()
    
  • 派生示例
    class Animal:
    def run(self):
    print(‘一天到晚跑个不停’)

    class Cat(Animal):
        def eat(self):
            print('猫喜欢吃鱼')
    
    c = Cat()
    c.run()
    
    # 添加的属性
    c.name = '加菲'
    
    print(c.name)
    # 衍生的方法
    c.eat()
    
  • 方法重写
    class Animal:
    def run(self):
    print(‘小动物喜欢到处跑’)

            def eat(self):
                print('小动物喜欢吃东西')
                
        class Cat(Animal):
            # 父类方法完全不合适,覆盖重写
            def run(self):
                print('猫喜欢走猫步')
    
        	# 父类的方法不够完善,需要添加完善
        	def eat(self):
                # 保留父类方法的内容
                # Animal.eat(self)    # 不建议使用
                # super(Cat, self).eat()
                super().eat()           # 推荐使用
                # 添加完善的内容
                print('猫喜欢吃鱼')   
    
        c = Cat()
        c.eat()
        c.run()
    
  • 多继承:一个类可以有多个父类
    class A:
    def test(self):
    print(‘in class A func test…’)

    class B:
        def test(self):
            print('in class B  func test...')
    
        def eat(self):
            print('in class B func eat ...')   
            
    class C(A, B):
        def eat(self):
            # 默认的方式找父类,跟不重写方法时的顺序是一样的,
            # 按照书写的先后顺序,默认是写在前面的类的方法
            # super().eat()
            # 明确指定调用哪个父类的方法
            B.eat(self)
    
    c = C()
    c.test()
    c.eat()        
    
  • 权限管理
    class Person:
    def init(self, name, age):
    self.name = name
    # 定义私有属性
    self.__age = age

          def test(self):
              # 私有属性和方法可以在类的内部使用
              print(self.__age)
              self.__hello()
              
          # 定义私有方法
          def __hello(self):
              print('for test')
              
    class Man(Person):
    	def show(self):
          	# 私有属性和方法在子类也不可以使用
          	print(self.__age)
            
    p = Person('老王', 38)
    print(p.name)
    # 属性前添加连个下划线,类的外部不能使用
    # print(p.__age)
    
    # 默认在添加两个下划线的属性名前添加了'_类名'
    # print(p.dict)
    # 强烈建议不要这样使用
    # print(p._Person__age)
    
    p.test()
    # p.__hello()
    m = Man('小明', 18)
    # m.show()
    
  • 类属性
    class Person:
    # 类属性,属于整个类
    # nation = ‘中国’

        # 限制对象可以使用的属性,可以提高效率,节约存储空间
        __slots__ = ('name', 'age', 'nation')
    
        def __init__(self, name):
            # 成员属性,属于某个对象
            self.name = name
            # 成员属性,当不存在会会试着找一下类属性
            # self.nation = 'xxx'
    
        def test(self):
            pass
    
    # 通过类名访问类属性
    # print(Person.nation)
    
    p = Person('王大花')
    # 可以通过对象访问类属性,但是不建议
    print(p.name)
    # print(p.nation)
    
    p.age = 20
    # p.height = 180
    
    # 特殊的类属性
    # 类名字符串
    print(Person.__name__)
    
    # 父类组成的元组
    print(Person.__bases__)
    
    # 类相关的信息
    print(Person.__dict__)
    
    print(Person.__slots__)
    
  • 类方法

    • 说明

      • 提通过类名进行调用
      • 定义时需要使用装饰器classmethod
    • 作用:

      • 可以创建对象或者简洁的创建对象
      • 可以对外提供简单易用的接口
    • 示例1:
      class Person:
      # 成员方法,通过对象进行调用
      def eat(self):
      print(‘红烧鸡腿我喜欢吃’)

      # 类方法,通过类名进行调用
        @classmethod
        def test(cls):
            # cls表示当前类
            print(cls, '类方法')
      
      	# 创建对象
        @classmethod
        def create(cls):
            obj = cls()
            obj.age = 1
            return obj     
      

      p = Person()
      p.eat()
      Person.test()

      创建或者简洁的创建对象

      p2 = Person.create()
      print(type(p2))

    • 示例2:
      class Number:
      def init(self, num1, num2):
      self.num1 = num1
      self.num2 = num2

          def add(self):
              return self.num1 + self.num2
      
          def sub(self):
              return self.num1 - self.num2
      
          def mul(self):
              return self.num1 * self.num2
      
          def div(self):
              if self.num2 == 0:
                  return None
              return self.num1 / self.num2
      
          # 对外提供简单易用的接口
          @classmethod
          def pingfanghe(cls, num1, num2):
              n1 = cls(num1, num1)
              n12 = n1.mul()
              n2 = cls(num2, num2)
              n22 = n2.mul()
              n3 = cls(n12, n22)
              return n3.add()
              # 计算3^2 + 4^2
              # n1 = Number(3, 3)
              # n12 = n1.mul()
              # n2 = Number(4, 4)
              # n22 = n2.mul()
              # n3 = Number(n12, n22)
              # ret = n3.add()
              # print(ret)
              print(Number.pingfanghe(3, 4))
      
  • 静态方法

    • 说明:

      • 通过装饰器staticmethod修饰
      • 通过类名进行调用
    • 示例:
      class Person:
      # 静态方法:没有cls参数
      @staticmethod
      def test():
      print(‘static method test …’)

          # 静态方法:可以创建对象
          @staticmethod
          def create():
              p = Person()
              p.age = 1
              return p
          
      Person.test()
      p = Person.create()
      print(type(p))  
      
    • 总结:

      • 凡是静态方法能够解决的问题类方法都能解决
      • 若方法中没有涉及类名的操作,可以使用静态方法代替类方法

多态特性

  • 定义:不同的对象,调用相同的方法,会有不同的响应

  • 示例:
    class Animal:
    def run(self):
    print(‘小动物走道都不一样’)

    class Cat(Animal):
        def run(self):
            print('猫都的是猫步')
            
    class Dog(Animal):
        def run(self):
            print('狗一般都走S型')
            
    def func(obj):
        obj.run()
     
    func(Cat())
    func(Dog())
    

属性函数

  • 说明:可以将成员方法当做属性一样访问

  • 作用:获取时以及设置指定属性时都可以进行人为干预,可以保护特定属性

  • 示例:
    class User:
    def init(self, username, password):
    self.username = username
    self.__password = password

        # 可以将方法像访问属性一样访问
        @property
        def test(self):
            return 'hello'
    
        # 保护指定的属性
        @property
        def password(self):
            print('大哥,有人想偷看密码')
            return '哈哈,让你偷看,没门'
    
        # 在设置对应属性时会自动调用
        @password.setter
        def password(self, password):
            print('密码设置', password)
            # 人为干预密码的设置过程,如:加密存储密码
            self.__password = 'xxx' + password + 'yyy'
            
    u = User('大狗', '123456')
    # u.test()
    # print(u.test)
    print(u.password)
    u.password = '654321'
    print(u.__dict__)
    

虚拟环境

  • 为什么要使用虚拟环境?
    • 在同一个环境下,不同软件依赖同一软件包的不同版本,为了进行环境隔离就出现了虚拟环境
  • 虚拟环境创建工具:virtualenv
    • pip install virtualenv
  • 创建虚拟环境
    • virtualenv 虚拟环境目录名
  • 激活虚拟环境
    • 虚拟环境目录\Scripts\activate.bat
  • 退出虚拟环境
    • 虚拟环境目录\Scripts\deactivate.bat
  • 快速复制一个虚拟环境
    • 冷藏现有的虚拟环境:pip freeze > requirements.txt
    • 创建一个新的虚拟环境:virtualenv venv
    • 激活虚拟环境:venv\Scripts\activate.bat
    • 安装依赖:pip install -r requirements.txt
  • 虚拟环境管理工具:virtualenvwrapper-win
    • 安装:pip install virtualenvwrapper-win
    • 说明:默认会将虚拟环境保存在C:\Users\用户名\Envs目录下
    • 查看虚拟环境:lsvirtualenv
    • 创建虚拟环境:mkvirtualenv
    • 启动虚拟环境:workon 虚拟环境名
    • 退出虚拟环境:deactivate.bat
      import pickle

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

def __str__(self):
    return 'name:{} age:{}'.format(self.name, self.age)
    xiaoming = Person('xiaoming', 20)# print(xiaoming)
    # 序列化:会将对象转换为bytes
    # s = pickle.dumps(xiaoming)
    # print(s)
    # 反序列化:从bytes中解析出对象
    # xm = pickle.loads(s)
    # print(xm, type(xm)) 
    # 直接保存到文件
    # fp = open('data.txt', 'wb')
    # pickle.dump(xiaoming, fp)
    # fp.close()
    # 从文件中读取对象
    fp = open('data.txt', 'rb')
    xm = pickle.load(fp)
    print(xm, type(xm))

猜你喜欢

转载自blog.csdn.net/weixin_44146168/article/details/85725853