w7

本周内容总结

派生方法的实战总结

# json 模块只能序列化指定的数据类型 而且要求数据类型的内部也要是指定的数据类型
这时候就可以看出派生的方法的重要性
代码实现:
	class MyJsonEncoder(json.JsonEncoder):
        def default(self,o):
            '''
            :param o: 接收无法被序列化的数据
        	:return: 返回可以被序列化的数据
            '''
            if isinstance(o,datetime.datetime):  # 判断是否是datetime类型 如果是久处理成可被序列的类型
                return o.strftime(%Y-%m-%d %X)
            elif isinstance(o,datetime.date):
                return o.strftime(%Y-%m-%d)
            return super().default(o)  # 最后调用原来的方法 这样就防止了一些额外操作没有做
        
        res = json.dumps(d,cls = MyJsonEncoder)
        print
'''
使用继承的方法来做到拦截操作 然后经过处理后再将数据返回
'''

面向对象三大特征之封装

封装:就是将数据和功能全部'隐藏'起来
隐藏:将数据和功能隐藏起来让用户无法直接获取使用 而是通过开放的窗口调用
伪装:将类里边的方法伪装成数据值
'''
使用类中的方法(函数)需要点函数命名加括号的形式但经过伪装的处理可以不需要括号也可以使用
'''
class MyCalss:
    school_name = '清华大学'
    _ = 'hhh'
    __age = 99
    # 类在定义阶段 变量名如果是两个下划线 那么就会被隐藏 在类外无法直接被调用
    # 这种隐藏并不是正在意义上的隐藏 仅仅是换了一个名字
obj = MyClass()
obj.__name = 'aaa'  # 无法被隐藏 只有在类定义阶段才行
'''
如果我们使用MyClass.__dict__的方式可以查看到隐藏了的
再使用print(MyClass._MyClass__age)
所以并不是真正的被隐藏了
因为无法做到真正的隐藏所以在类的定义阶段如果代码中有下划线开头的变量名或者是方法我们就不要直接去使用了 而是去找下面可能定义的接口
'''

伪装

# 将类里边的方法伪装成数据值
代码实现:
class Person(object):
    def __init__(self,name,hegiht,weight):
        self.name = name
        self.hegiht = height
        self.weight = weight
        
    @prperty
    def BMI(self):
        return self.weight/(self.hegiht ** 2)
    
p1 = Person('aaa', 180, 160)
没有伪装:p1.BMI()
利用@prperty
就可以直接点出来
print(self.BMI)

面向对象三大特征之多态

#多态:多态就是一种事物的多种表达形态
例如水有固态 气态 液态

class Anmimal:
    pass

class Cat(Anmimal):
    def miao():
        print('喵喵喵')
        
class Dog(Anmimal):
    def wang():
        print('汪汪汪')
        
# 但在作为动物 他们都会叫
'''
面向对象多条的意思是 一种事物可以有多种形态但是针对相同的功能应该有定义相同方法
这样无论我们拿到的具体是哪个具体的事物 都可以通过相同的方法调用功能
'''
class Anmimal:
    def spark(self):
    	#叫的方式
    	pass
    
class Cat(Anmimal):
    def spark(self):
        print('喵喵喵')

意义:
	假设我们使用相同的功能去操作不同类型的数据 就可以节省代码
    eg:
    	l1 = [1,2,3]
        s1 = '123'
        d1 = {'1':0,'2':2}
        print(l1.__len__)
        print(s1.__len__)
        print(d1.__len__)
        面对不同数据类型的数据 我们就可以使用相同的方法来计算
'''
鸭子类型🦆:只要看上去像鸭子走路像鸭子 那么就是鸭子
'''
# linux 系统
'''
文件		能够读取数据和存储数据
内存		能够读取数据和存储数据
硬盘		能够读取数据和存储数据
所以在linux系统中 一切皆文件
'''
python提倡自由简介大方 不约束程序员的行为 但是多态提供了约束的办法
import abc

#指定metaclass属性将类设置为抽象类,抽象类本身只用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod  # 该装饰器限制子类必须定义有一个为talk的方法
    def talk(self):  # 抽象方法无需实现具体功能
        pass
    
    
class Cat(Animal):	# 但凡继承了Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass
    
cat = Cat()  # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

面向对象之反射

使用字符串来操作对象数据和方法:
1.hasattr()
	判断对象是否含有某个字符串
2.getattr()
	获取对象中对应字符串的数据值或方法名
3.setattr()
	根据字符串给对象或者修改数据
4.delattr()
	根据字符串中删除对象里的名字

class C1:
    school_name = '清华大学'
    
    def choice_course(self):
        print('正在选课')
        
obj = C1()
# 推导思路
'''判断某个名字对象是否可以使用(存在)'''
try:
    obj.xxx
except AttributeError:
    print('没有该名字')
'''判断用户随意指定的随意的名字是否可以使用(存在)'''
target_name = input('输入你的名字>>>:').strip()
try:
    obj.target_name
except AttributeError:
    print('没有该名字')

反射实战案列

1.什么时候该考虑使用反射 只要需求出现了关键字
	对象...字符串...
2.实战案例
	1.模拟cmd终端
    	class Wincmd:
            def tasklist(self):
                print('''
                1.学习
                2.学习
                3.学习
                ''')
            def ipconfig(self):
                print('''
                地址:12.122.145
                地址:上海浦东新区
                ''')
            def get(self,target_file):
                print('获取指定内容',target_file)
            def put(self,target_file):
                print('上传指定文件',target_file)
            def server_run(self):
                print('欢迎进入简易版本的cmd终端')
                while True:
                    target_cmd = input('请输入你的指令>>>:')
                    res = target_cmd.split(' ')
                    if len(res)==1:
                        if hasattr(self,res[0]):
                            getattr(self,res[0])()
                        else:
                            print(f'{res[0]}不是内部或外部指令')
                     elif len(res)==2:
                        if hasattr(self,res[0]):
                            getattr(self,res[0])(res[1])
                        else:
                            print(f'{res[0]}不是内部或外部指令')
          obj = Wincmd()
          obj.server_run()
         
	2.一切且对象
    	# 利用反射保留某个py文件中所有大写对应的变量名及对应的数据值
        import settings
        print(dir(settings))   # dir列举对象可使用的名字
        
        useful_dict = {}
        for name in dir(settings):
            if name.isupper():
                useful_dict[name] = getattr(settings,name)
        print(useful_dict)
        
        while True:
            target_name = input('请输入名字>>>:')
            if hasattr(settings,target_name):
                print(getattr(setings,target_name))
            else:
                print('模块中没有该名字')

面向对象的魔法方法

魔法方法是就是不需要调用 当满足了某一个条件就会自动触发
魔法方法: 在类中的双下方法都是魔法方法(__init__)

常见的魔法方法

魔法方法 使用/触发条件
__ init __ 对象添加独有的数据对象添加独有的数据
__ str __ 对对象进行打印操作
__ call __ 对对象调用括号触发
__ getattr __ 对象点一个不存在的名字时
__ getattribute __ 不管对象点的名字存不存在都会触发
__ setattr __ 给对象添加或者修改数据触发
__ enter __ 当有上下文管理操作触发 该方法返回什么 as后面的变量名接收什么
__ exit __ with上下文管理语法运行完毕之后自动触发(子代码结束)

魔法方法笔试题

1.补全下列代码使得运行不报错即可
    class Context:
        pass
    with Context() as f:
        f.do_something()
2.自定义字典类型并让字典能够通过句点符的方式操作键值对

答案:https://www.cnblogs.com/xiaochenxiangchangpang/p/16870516.html

元类的介绍

'''推导流程1:如何查看数据的数据类型?'''
	我们查看一个数据类型都是使用 type来进行查看的
    l1 = [1,2,3,4]
    d1 = {'1':1,'2':2}
    print(type(l1))   # <class list>
    print(type(d1))   # <class dict>
	可见结果是一个类
'''推导流程2:其实type方法就是用来查看产生对象的类名'''
	class Student:
        pass
    
    obj = Student()
    print(type(obj))   # <class '__main__.Student'>
'''推导流程3:在python中一切皆对象 好奇如果在对Student进行查看'''
	print(type(Student)) # <class 'type'>

创建类的两种方式

在 type 注释中可以查找
1.使用关键字 class
2.使用特殊句式
type(类,父类,名称空间)

元类定制类的产生方式

'''
推导
	对象是由类名加括号产生的	__init__
	类时由元类加括号产生的		__init__
'''
"""产生的类必须是大写字母开头 负责无法产生"""
#1.自定义一个元类 并继承type
class Mytype(type):
    def __init__(cls,what,bases=None, dict=None):
        if not what.istitle():
            raise TypeError('类名必须开头大写')
        super().__init__(what,bases,dict)
        
class aaa(metaclass = Mytype):
    pass

class Aaa(metaclass = Mytype):
    pass

这样就会拦截类名不是大写开头的 并主动报错 如果是大写开头则正常进行

元类定制对象的产生方式

'''
推导:
	对象加括号会执行产生对象类里面的	__call__
	类名加括号会执行该类里的		   __call__
'''
"""对象必须有独有的数据 必须采用关键字传参"""
class MyMetaclass(type):
    def __call__(self,*args,**kwargs):
        # 1.产生一个空对象(骨架)
        # 2.调用__init__给对象数据
        # 3.返回创建好的对象
        if args:
            raise TypeError('寄')
        return super().__call__(*args,**kwargs)
    
class Student(metaclass = MyMetaclass):
    def __init__(self,name,age):
        self.name = name
        self.age = age
        
obj = Student('xiaochen',18)		# 会直接报错 因为不是关键字传参
obj1 = Student(name = 'xiaochen',age='18')

魔法方法之双下new(new)

class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        # 1.产生一个空对象(骨架)
        obj = self.__new__(self)
        # 2.调用__init__给对象添加独有的数据(血肉)
        self.__init__(obj,*args, **kwargs)
        # 3.返回创建好的对象
        return obj


class Student(metaclass=MyMetaClass):
    def __init__(self, name):
        self.name = name

obj = Student('jason')
print(obj.name)
# 重点就是一句话>>>: __new__可以产生空对象
'''你没对象我给你new一个'''

设计模式简介

设计模式的意义:
	前人通过大量的验证创造出来的解决问题固定的高效的方法
设计模式可以分为23种 三大类
	创建类 结构类 行为类
在这二十三种之中我们需要掌握一个比较特别的>>>单列模式
	作用:在我们使用类加括号就会产生出一个新的对象 并且每一个对象都不一样但是使用单类模式我们就可以限定只产生一个对象
    目的:
    	当类中有许多非常强大的办法 我们在程序中很多地方都需要使用
    	如果不做单例 会产生很多无用的对象浪费存储空间
    	如果使用单列 那么程序就只有一个对象

单列模式的常见实现方式

#方式一
	class C1:
        __instance = None
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        @classmethod
        def singleton(cls):
            if not cls.__instance:
                cls.__instance = cls('jason',18)
            return cls.__instance

	obj = C1.singleton()
    obj1 = C1.singleton()
    obj2 = C1.singleton()
    此时上面三个对象是一个东西 但我们可以传入参数来创造不同的对象
    obj3 = C1('tt',28)
    obj4 = C1('aa',38)
    此时这两个对象是不一样的
    
#方式二
	class Mymeta(type):
        def __init__(self,name,bases,dic):
            self.__instance =  object.__new__(self)
            self.__init__(self,__instance,'jason',18)
            super().__init__(name,bases,dic)
            
        def __call__(self,*args,**kwargs):
            if args or kwargs:
                obj = object.__new__(self)
                self.__init__(obj,*args,**kwargs)
                return obj
            return self.__instance
        
     class Mysql(metaclass = Mymeta):
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
    obj1 = Mysql()
    obj2 = Musql()
    在创建对象不传入参数时 无论创造多少个对象都是一样的
    
#方式三
	class C1:
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
     obj = C1('xiaochen',19)
     '''将上述封装到一个py文件中 只需要调用这个文件的obj即可'''
        
#方式四
	def outer(cls):
        _instance = cls('xiaochen',19)
        def inner(*args,**kwargs):
            if args or kwargs:
                obj = cls(*args,**kwargs)
                return obj
            return _insance
        return inner
    @outer
    class Mysql:
        def __init__(self,host,port):
            self.host = host
            self.port = port
            
   obj = Mysql()      
	只要不传参那么生成的对象就是不变的

pickle序列化模块

#优势:能够序列化所有数据类型的数据(包括对象)
#劣势:只能在python中使用 并且无法跨语言传输

实例 (做到将对象并保存 再拿出来时还是一个对象)
class C1:
    def __init__(self,name,age):
        self.name = name
        sele.age = age
        
    def func1(self):
        print('from func1')
        
obj = C1('xiaochen',19)

import json
with open('a.txt','w',encoding = 'utf8')as f:
    json.dump(obj,f)
'''之前所学的json模块无法解决此类问题'''
import pickle
with open('a.txt','wb')as f:
    pickle.dump(obj,f)  # 注意模式选择要是二进制
with open('a.txt','rb')as f:
    data = pickle.load(f)
print(data)
print(data.name)
均可以执行 说明>>>该读取的数据就是一个对象
posted @ 2022-11-13 17:07  早点早点灬  阅读(596)  评论(0)    收藏  举报