• 初识面向对象四(装饰器/反射)


    常用装饰器

    @classmethod
    @property
    @staticmethod
    class A:
    __count = 0 # 隐藏了count属性
    def __init__(self,name):
    self.name = name
    self.__add_count() # 每一次实例化的时候调
    # 用私有方法来对__count进行累加
    @classmethod
    def __add_count(cls): # 定义一个私有的方法
    # print(cls,A)
    cls.__count += 1 # 让这个方法只能在类的内部被使用

    @classmethod # 被classmethod装饰器装饰的方法,都有一个默认的参数,这个参数就是当前类
    def show_count(cls): # 定义一个普通方法,
    # print(cls,A)
    return cls.__count # 让用户可以从外部查看__count的值

    def eat(self):
    print('%s在吃饭'%self.name)
    print(A.show_count())
    alex = A('alex')
    print(alex.show_count())
    yuan = A('yuan')
    print(A.show_count())
    有的时候,
    在类中会有一种情况,就是这个方法并不需要使用某一个对象的属性
    因此 这个方法中的self参数是一个完全无用的参数
    show_count是一个查看类中属性的方法,这样的方法和某一个对象并没有直接联系

    本质上 : 一个方法不用对象属性但是使用静态属性 -- 类方法@classmethod
    某一个方法被创造出来,就是为了进行对静态变量进行操作
    根本不涉及到对象
    所以这个方法就应该被定义成 类方法(被@classmethod装饰)
    调用这个类方法,可以使用对象调用,也可以使用类调用
    但是这个方法的默认参数永远是当前类的命名空间,而不是对象的

    如果一个类中的方法不用对象属性也不用静态属性 -- 静态方法@staticmethod
    那实际上这个方法就是一个普通的函数
    class Student():pass
    class Manager():pass
    def login(arg1, arg2): # 全局的名字 函数的名字
    print(arg1, arg2)

    login(1,2)
    先登录
    在登陆的过程中知道了用户的身份 : Manager Student
    之后再进行实例化

    纯面向对象编程
    class User(object):
    @staticmethod
    def login(arg1,arg2): # 是User类中的名字 函数的名字 login就是一个类中的静态方法,本质上就是一个函数
    print(arg1,arg2)
    return (arg1+arg2)
    class Student(User):pass
    class Manager(User):pass

    ret = User.login(1,2)
    print(ret)

    如果在上面的例子中,没有Student类,只有一个角色,就是Manager类
    class Manager(object):
    @staticmethod
    def login(arg1, arg2): # 是User类中的名字 函数的名字 login就是一个类中的静态方法,本质上就是一个函数
    print(arg1, arg2)
    return (arg1 + arg2)

    ret = Manager.login(1,2)
    print(ret)

    普通的方法 类方法 静态方法
    默认参数 self cls 无
    操作的变量 操作对象的属性 操作静态属性 既不操作对象属性,也不操作类的属性
    所属的命名空间 类 类 类
    调用方式 对象 类/对象 类/对象
    对应的装饰器 无 @classmethod @staticmethod

    学生选课系统
    class Student:
    def __init__(self):
    # self :属于这个学生自己的一块空间
    self.courses = []

    @staticmethod
    def show_courses(): # 不是查看已选课程,而是查看所有课程 -- 静态方法
    # 不是操作学生对象本身空间中的数据,而是所有的学生这个方法的结果都是一样的
    print('打开课程文件,一个一个读出来')

    def select_courses(self): # 选课 是一个对象方法(普通的方法)
    self.courses.append('某一门课程') # 操作的课程一定是属于某一个对象

    Student.show_courses()
    alex = Student()
    alex.show_courses()
    一个不需要用到对象命名空间中的变量的方法,就不是一个对象方法,就应该是一个普通的函数


    class Student:
    文件的路径 = 'student.info'
    def __init__(self):
    # self :属于这个学生自己的一块空间
    self.courses = []

    @classmethod
    def show_courses(cls): # 由于查看文件需要用到Student类中的一个静态属性 -- 类方法
    print('打开课程文件%s,一个一个读出来'%cls.文件的路径)

    def select_courses(self): # 选课 是一个对象方法(普通的方法)
    self.courses.append('某一门课程') # 操作的课程一定是属于某一个对象

    Student.show_courses()
    abc = Student()
    abc.show_courses()



    用哪一个命名空间中的名字,就定义不同的方法
    只要用self 就是普通方法,只能用对象调
    只要用cls 就是类方法,可以用类,可以用对象
    啥也不用 就是静态方法,可以用类,可以用对象

    私有的
    私有的普通方法
    私有的类方法
    私有的静态方法

    巧用装饰器思想

    先定义类
    写方法
    写具体的方法中的代码
    写完之后,发现没有用到self,那么如果用到类,就定义成类方法,如果啥也没用到,静态方法

    先定义函数
    写函数
    写具体函数中的代码
    写完之后,发现要挪进类里,如果啥也没用到,静态方法;如果用到类,就定义成类方法


    细说@property(重要)
    # @property
    # 例1 - 1 (某一个属性如果是通过计算得来的,那么计算的过程写在方法里,把这个方法伪装成属性)
    # from math import pi
    # class Circle:
    # def __init__(self,r):
    # self.r = r
    #
    # @property # 把一个方法伪装成属性 源码中有人写
    # def area(self): # 被property装饰器装饰的方法不能传递除self以外的参数
    # return pi*self.r**2
    #
    # @property
    # def perimeter(self):
    # return self.r*pi*2
    #
    # c1 = Circle(5)
    # print(c1.area)
    # c1.r = 10
    # print(c1.area)
    # 圆c1的面积周长
    # alex的名字

    # class Circle:
    # def __init__(self,r):
    # self.r = r
    # self.area = pi*self.r**2
    # self.perimeter = self.r*pi*2
    #
    # c1 = Circle(5)
    # print(c1.area)
    # c1.r = 10
    # print(c1.area)

    # 例2-1 某一个属性需要被私有化,又需要能被外部查看,这种情况,把这个属性通过方法返回,方法伪装成属性
    # class Person:
    # def __init__(self,name):
    # self.__name = name # 不让外面随便修改
    # def get_name(self):
    # return self.__name
    #
    # alex = Person('alex')
    # print(alex.get_name())

    # 例2-2
    # class Person:
    # def __init__(self,name):
    # self.__name = name # 不让外面随便修改
    #
    # @property
    # def name(self):
    # return self.__name
    #
    # alex = Person('alex')
    # print(alex.name)

    # 例2-3 修改属性值
    class Person:
    def __init__(self,name):
    self.__name = name # 不让外面随便修改

    @property
    def name(self):
    return self.__name

    @name.setter # 之前必须有一个同名的方法被property装饰过
    def name(self,new_name):
    if type(new_name) is str:
    self.__name = new_name

    @name.deleter
    def name(self):
    del self.__name

    def set_name(self,new_name):
    if type(new_name) is str:
    self.__name = new_name

    abc = Person('abc')
    print(abc.name)
    # alex.set_name(123)
    # print(abc.name)
    abc.name = 'abc123'
    print(abc.name)
    del abc.name # 只是相当于调用被deleter装饰的方法,并不相当于删除name属性
    print(abc.name)


    反射
    某个命名空间中的某个"变量名",获取这个变量名对应的值
    你有没有什么时候
    能拿到 字符串
    你就希望能够通过这个字符串 --> 程序中的变量名(类名函数名变量名方法名对象名)

    class Manager:pass
    class Student:pass
    class Teacher:pass
    identify = 'Student'
    print(eval(identify)())
    if 'identify' == 'Manager':
    Manager()
    elif 'identify' == 'Student':
    Student()
    elif 'identify' == 'Teacher':
    Teacher()

    class Person:
    role = '人类'
    Country = '中国'

    attr = input('>>>') # role 人类
    # # Country 中国
    # print(getattr(Person,'role'))
    # print(getattr(Person,'Country'))
    if hasattr(Person,attr):
    print(getattr(Person,attr))

    if attr == 'role':
    print(Person.role)
    elif attr == 'Country':
    print(Person.Country)


    getattr(命名空间,'key') == 命名空间.key
    所有的a.b都可以被反射成getattr(a,'b')

    反射类中的方法
    class Person:
    role = '人类'
    @staticmethod
    def show_courses():
    print('所有课程')
    Person.role == getattr(Person,'role')
    Person.show_courses() == getattr(Person,'show_courses')()
    ret = getattr(Person,'show_courses')
    ret()

    类名.静态属性/类名.类方法/类名.静态方法
    list /[1,2,3].append()
    对象.对象属性/对象.普通方法/对象.类方法/对象.静态方法

    模块名.方法名
    import time
    import math
    print(time.time()) #'time'
    print(getattr(time,'time')())
    print(getattr(math,'pi'))


    getattr(类名,"静态属性")
    getattr(类名,"类方法")()
    getattr(类名,"静态方法")()

    getattr(对象名,"对象属性")
    getattr(对象名,"方法")()
    getattr(对象名,"类方法")()
    getattr(对象名,"静态方法")()

    getattr(模块,"全局变量")
    getattr(模块,"函数名")

    类对象模块 实际上都是有自己的命名空间,从这个命名空间中获取某个值或者函数...名字
    如果这个名字是字符串数据类型
    值 = getattr(命名空间,字符串类型名字)
    如果getattr的值是一个属性或者普通的变量 那么直接得到结果
    如果getattr的值是函数或者方法 那么只能得到地址,需要我们手动加括号来调用

    4. 反射全局变量的值(反射本文件中的名字)
    from sys import modules
    a = 1
    b = 2
    lst = [1,2,3]

    class Manager:pass
    class Student:pass
    class Teacher:pass
    getattr(modules[__name__],'Student')
    identify = input('>>>').strip()
    类 = getattr(modules[__name__],identify)
    print(类)
    对象 = 类()
    print(对象)


    if 'identify' == 'Manager':
    Manager()
    elif 'identify' == 'Student':
    Student()
    elif 'identify' == 'Teacher':
    Teacher()


    归纳总结
    什么是封装?
    广义上
    狭义上
    类的命名空间(类的对象共享的资源) :
    静态属性
    类方法
    静态方法
    普通方法
    property方法
    对象的命名空间(对象独有的资源):
    对象的属性
    对象的方法

    狭义上
    私有成员
    在类的内部 __成员名
    在类的外部 不能用
    在存储的空间中 _类名__成员名

    1.私有成员不能在类的外部使用,也不能被继承
    无论在哪个类中调用私有成员,一定是在哪个类调,就用哪个类的
    经典的面试题
    class Foo(object):
    def __init__(self):
    self.__func() # _Foo__func
    # self.func()
    def __func(self):print('in Foo __func') # _Foo__func
    def func(self):print('in Foo func')

    class Son(Foo):
    def __func(self):print('in Son __func') # _Son__func
    def func(self):print('in Son func')

    2.类中的三个装饰器方法
    先实现功能
    某个方法如果用到self 传self
    某个方法如果没用到self,用到类 传cls ,加@classmethod装饰器 *****
    某个方法如果没用到self,没用到类 啥也不传,加@staticmethod装饰器
    但凡是不需要传self参数的,都不需要实例化,直接使用类调用就可以了
    @property : 伪装一个方法成为一个属性,调用的时候不需要加()

    3.反射 非常重要
    a.b这样的情况
    如果由于某种原因,b变成了 'b'
    那么就是用getattr(a,'b')的形式获取b对应的值
    如果b是一个值 那么getattr的结果就是值
    如果b是一个地址 那么getattr的结果就是地址,地址()就是执行
    from sys import modules
    getattr(modules[__name__],'全局变量名')
    从当前文件中寻找全局变量对应的值/地址


    from sys import modules
    a = 2
    b = 4
    print(getattr(modules[__name__],'b'))
     


     


  • 相关阅读:
    java 设计模式 (一)
    多Linux安装
    华北电力大学 研究生学院 笔记
    电力大学 专升本
    19年 考研究生 过程
    netcat-flume-logger
    大神写的K8S 二进制安装笔记
    非常全的Mybatis学习笔记
    Docker-compose部署gitlab
    docker-compose 配合 dockerfile使用
  • 原文地址:https://www.cnblogs.com/Godisgirl/p/10022662.html
Copyright © 2020-2023  润新知