面对对象高阶+反射+魔法方法+单例(day22)

时间:2022-02-16 02:07:48

昨日内容

组合

  1. 一个类产生的对象时另一个对象的属性
  2. 目的:减少代码冗余

封装

  1. 把一堆属性封装到一个对象中

  2. 目的:方便存取(通过对象.属性的方式对数据进行存取)

  3. 如何封装

    1. 类内部定义
    2. 通过对象.属性的方式添加属性
  4. 访问限制机制

    1. 在类内部,凡是以__开头的属性都不能被外部直接访问,python对其作了变形(隐藏)

      例如:__属性 变形为 __类名__属性

    2. 目的:防止使用者在外部对隐私数据进行访问,保护数据安全

property装饰器

用来装饰在类内部的函数中,使该方法不用加括号调用

多态

  1. 同种事物的多种形态

  2. 目的:让父类定义一套标准,子类遵循父类定义的标准

    ​ 总结:为了统一类的编写规范

  3. 实现方式

    1. 子类继承父类,遵循父类的方法
    2. 子类继承抽象类,强制子类必须遵循父类的标准
    3. 鸭子类型

鸭子类型

  1. 只要看起来像鸭子,那么就是鸭子类型
  2. 在不知道对象是什么情况下,拥有相同的方法

今日内容

classmethod

  1. 类内部方法的装饰器,是该方法绑定给类使用(类的绑定方法)
  2. 作用:由类来调用,会将类当作第一个参数传给该方法
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    @classmethod
    def tell_info(cls):
        print(cls)

 p =People('wick',24)
p.tell_info()
People.tell_info()      

staticmethod

  1. 类内部方法的装饰器,使该方法不与类和对象绑定
  2. 作用:类和对象调用,不用传参数
import uuid
import hashlib
class People:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    @staticmethod
    def create_id():
        uuid_id = uuid.uuid4()
        return uuid_id

 p =People('wick',24)
print(p.create_id())
print(People.create_id())

面对对象高级

isinstance

python内置的函数,可以传入两个参数,用于判断参数1是否是参数2的一个实例(判断一个对象是否是一个类的实例)

class Foo:
    pass

class Goo:
    pass

foo_obj = Foo()
print(Foo.__dict__)  # 获取当前类的属性
print(foo_obj.__class__)  # 获取当前对象所属的类
print(isinstance(foo_obj,Foo))  # True
print(isinstance(foo_obj,Goo))  # False

issubclass

python内置函数,可以传入两个参数,用于判断参数1是否是参数2的子类(判断一个类是否是另一个类的子类)

class Foo:
    pass

class Goo:
    pass

print(issubclass(Goo,Foo))  # False

反射(重要)

指的是通过“字符串”对对象或类的属性进行操作

  1. hasattr:通过字符串判断对象或类是否存在该属性
  2. getattr:通过字符串,获取对象或类的属性
  3. setattr:通过字符串,设置对象或类的属性
  4. delattr:通过字符串,删除对象或类的属性
class People:
    country = 'China'
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

p = People('wick',24,'man')

# 普通方式
print('name' in p.__dict)  # True
print('country' in People.__dict__)  # True
# hasattr
print(hasattr(p,'name'))  # True

# 普通方式
print(p.__dict__.get('name'))  # wick
print(p.__dict__.get('name1','9'))  # 9
# getattr
print(getattr(p,'name','tank'))  # wick
print(getattr(p,'name1','tank'))  # tank

# 普通方式
p.level = 10
print(p.level)  # 10
# setattr
setattr(p,'sal','3.0')
print(hasattr(p,'sal'))  # True

# 普通方式
del p.level
print(hasattr(p,'level'))  # False
# delattr
delattr(p,'sal')
print(hasattr(p,'sal'))  # False
#反射小练习
class Movie:
    def input_cmd(self):
        print('输出命令:')
        while True:
            cmd = input('请输入执行方法名:').strip()
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func()
            else:
                print('命令错误,请重新输入')

    def upload(self):
        print('电影开始上传')

    def download(self):
        print('电影开始下载')

movie_obj = Movie()
movie_obj.input_cmd()             

魔法方法(类的内置方法)

  1. 凡是在类内部定义,以__开头和__结尾的方法都称之为魔法方法,也叫类的内置方法

  2. 作用:魔法方法会在某些条件成立时触发

    __init__:在调用类时触发

    __str__:会在打印对象时触发,必须要返回值,必须是字符串类型

    __del__:对象被销毁前执行该方法

    __getattr__:会在对象.属性时,属性没有才会触发

    __setattr__:会在对象.属性 = 属性时触发

    __call__:会在对象被调用时触发

    __new__:会在__init__执行前触发

    class Foo(object):
    
        def __new__(cls, *args, **kwargs):
            print(cls)
            return object.__new__(cls)  # 真正产生一个空对象
    
        # 若当前类的__new__没有return一个空对象时,则不会触发。
        def __init__(self):
            print('在调用类时触发...')
    
        # def __str__(self):
        #     print('会在打印对象时触发...')
        #     # 必须要有一个返回值, 该返回值必须是字符串类型
        #     return '[1, 2, 3]'
    
        def __del__(self):
            print('对象被销毁前执行该方法...')
    
        def __getattr__(self, item):
            print('会在对象.属性时,“属性没有”的情况下才会触发...')
            print(item)
            # 默认返回None, 若想打印属性的结果,必须return一个值
            return 111
    
        # 注意: 执行该方法时,外部“对象.属性=属性值”时无效。
        def __setattr__(self, key, value):
            print('会在 “对象.属性 = 属性值” 时触发...')
            print(key, value)
            print(type(self))
            print(self, 111)
            self.__dict__[key] = value
    
        def __call__(self, *args, **kwargs):
            print(self)
            print('调用对象时触发该方法...')

单例模式

  1. 单例模式指的是单个实例,实例指的是调用类产生的对象

    实例化多个对象会产生不同的内存地址,单例可以让所有调用者在调用类产生对象时都指向同一个内存地址,比如打开文件

2 .目的:为了减少内存的只能用

# 要从配置文件中获取三个同样的文件名,会开辟三个空间

# 单例方式1
class File:
    __instance = None

    @classmethod
    def singleton(cls,file_name):
        if not cls.__instance:
            obj = cls(file_name)
            cls.__instance = obj
        return cls.__instance

    def __init(self,file_name,mode='r',encoding = 'utf-8'):
        self.file_name = file_name
        self.mode = mode
        self.encoding = encoding

    def open(self):
        self.f = open(self.file_name,self.mode,encoding = self.encoding)

obj1 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
obj2 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
obj3 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
# obj1 = File('jason雨后的小故事.txt')
# obj2 = File('jason雨后的小故事.txt')
# obj3 = File('jason雨后的小故事.txt')   

print(obj1)
print(obj2)
print(obj3)
        
# 单例方式2
class File:
    __instance = None

    def __new__(cls,*args):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance 

    def __init(self,file_name,mode='r',encoding = 'utf-8'):
        self.file_name = file_name
        self.mode = mode
        self.encoding = encoding

    def open(self):
        self.f = open(self.file_name,self.mode,encoding = self.encoding)

obj1 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
obj2 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
obj3 = File.singleton('jason雨后的小故事.txt')  # singleton(cls)
# obj1 = File('jason雨后的小故事.txt')
# obj2 = File('jason雨后的小故事.txt')
# obj3 = File('jason雨后的小故事.txt')    

print(obj1)
print(obj2)
print(obj3)