面向对象之 反射,双下方法

1. 反射

计算机科学领域主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)

python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

主要适用于四种情况:

1.对对象的反射

class Foo:
    f = '类的静态变量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

print(getattr(obj,'aaaaaaaa','不存在啊')) #报错

#设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,则报错

print(obj.__dict__)

对实例化对象的示例

2.对类的反射

class Foo(object):

    staticField = "old boy"

    def __init__(self):
        self.name = 'wupeiqi'

    def func(self):
        return 'func'

    @staticmethod
    def bar():
        return 'bar'

print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

3.当前模块的反射

import sys

def s1():
    print 'in s1 章超印'

def s2():
    print 'in s2 zcy'

this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

4.其他模块的反射

#一个模块中的代码
def test():
    print('from the test')
"""
程序目录:
    module_test.py
    index.py

当前文件:
    index.py
"""
# 另一个模块中的代码
import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

其他模块的示例

反射的应用:

了解了反射的四个函数。那么反射到底有什么用呢?它的应用场景是什么呢?

现在让我们打开浏览器,访问一个网站,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等,其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理。

没学反射之前

class User:
    def login(self):
        print('欢迎来到登录页面')

    def register(self):
        print('欢迎来到注册页面')

    def save(self):
        print('欢迎来到存储页面')

while 1:
    choose = input('>>>').strip()
    if choose == 'login':
        obj = User()
        obj.login()

    elif choose == 'register':
        obj = User()
        obj.register()

    elif choose == 'save':
        obj = User()
        obj.save()

学了之后

class User:
    def login(self):
        print('欢迎来到登录页面')

    def register(self):
        print('欢迎来到注册页面')

    def save(self):
        print('欢迎来到存储页面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user,choose):
        func = getattr(user,choose)
        func()
    else:
        print('输入错误。。。。')

学了反射之后解决方式
可以看出反射的益处:简单,一目了然

2. 函数 VS 方法

可以通过以下几种方式确定什么是函数,什么是方法

2.1 通过打印函数名(方法名)确定
def func():
    print("in func")

class A:
    def func(self):
        print("in A.func")

obj = A()
print(func)  # 函数       <function func at 0x000001AD5BB0D1E0>
print(A.func)  # 函数     <function A.func at 0x000001AD5BCBB598>
print(obj.func)  # 方法   <bound method A.func of <__main__.A object at 0x000001AD5BC11940>>
2.2 通过types模块验证
from types import FunctionType
from types import MethodType

def func():
    pass

class A:
    def func(self):
        pass

obj = A()

print(isinstance(func,FunctionType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True
2.3 静态方法就是函数
from types import FunctionType
from types import MethodType

class A:

    def func(self):
        pass

    @classmethod
    def func1(self):
        pass

    @staticmethod
    def func2(self):
        pass
obj = A()

# 静态方法其实是函数
# print(isinstance(A.func2,FunctionType))  # True
# print(isinstance(obj.func2,FunctionType))  # True

2.4 函数和方法的传参方式 (最直接的判断方式)

函数是显式传递参数

方法中的数据则是隐式传参

3. 双下方法

  1. _ new _ new一个对象 构造方法 ***
    class A:
        def __init__(self):
            self.x = 1
            print('in init function')
        def __new__(cls, *args, **kwargs):
            print('in new function')
            return object.__new__(A, *args, **kwargs)
    
    a = A()
    print(a.x)
    class A(object):
    
        def __init__(self):
    
            self.x = 1
            print('in init function')
    
        def __new__(cls, *args, **kwargs):
            print('in new function')
            return object.__new__(A)  # object 342534
    
    # # 对象是object类的__new__方法 产生了一个对象.
    a = A()
    
    # 类名()
    # 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
    # 2. 执行__init__方法,给对象封装属性.
    print(a)

    单例模式:

    # python中的设计模式: 单例模式
    #
    # 一个类只允许实例化一个对象.
    class A:
    
        pass
    obj = A()
    print(obj)
    obj1 = A()
    print(obj1)
    obj2 = A()
    print(obj2)
    
    # 手写单例模式
    class A:
        __instance = None
    
        def __init__(self,name):
            self.name = name
    
        def __new__(cls,*args,**kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
    obj = A('alex')
    print(obj)
    obj1 = A('周道镕')
    print(obj1.name)
    print(obj.name)

    ##### 单例模式具体分析

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

单例模式具体分析
2. _ str _ 打印对象触发 _ str _方法 ***

如果一个类中定义了_ _ str _ _方法,那么在打印 对象 时,默认输出该方法的返回值。

class A:

    def __init__(self,name,age):
        self.name = name
        self.age =age

    def __str__(self):
        print(666)
        return f'姓名: {self.name} 年龄: {self.age}'

a = A('赵海狗',35)
b = A('李业',56)
c = A('华丽',18)
# 打印对象触发__str__方法
print(f'{a.name}  {a.age}')
print(f'{b.name}  {b.age}')
print(f'{c.name}  {c.age}')
print(a)
print(b)
print(c)
# 直接str转化也可以触发.
print(str(a))
3. _ repr _ 打印对象触发 _ repr _方法 ***

如果一个类中定义了_ _ repr _ _方法,那么在repr(对象) 时,默认输出该方法的返回值。

class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '太白'
a = A()
print(repr(a))
print('%r'%a)

_ _ str_ _ repr _ _的区别:

class A:

    def __init__(self,name,age):
        self.name = name
        self.age =age

    def __str__(self):
        return '777'

    def __repr__(self):
        return '666'

a = A('赵海狗',35)
b = A('李业',56)
c = A('华丽',18)
print(a)

# 结果:
# 777
如果一个类里这两个方法同时存在,则先执行_ _ str _ _方法
4. _ _ call _ _ 对象() 自动触发对象从属于类(父类)的_ _ call _ _方法 ***

注:构造方法_ _ new _ 的执行是由创建对象触发的,即:对象 = 类名() ;而对于 _ call _ _ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')

obj = Foo()
obj()
5. _ _ len _ _
class B:
    def __len__(self):
        print(666)

b = B()
len(b) # len 一个对象就会触发 __len__方法。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))
6. _ _ hash _ _
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
7. _ _ eq _ _
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)
8. _ _ del _ _

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

9. _ _ item _ _系列
class A:
    def __init__(self,name):
        self.name = name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        print("del obj[key]时,执行")
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print("del obj.key时,执行")
        self.__dict__.pop(item)

a1 = A("zdr")
# a1["name"]
# a1["name"] = "zcy"
# print(a1.name)

# del a1["name"]
# a1.name

del a1.name
print(a1.name)
10. 上下文管理器相关

_ _ enter _ _ _ _ exit _ _

没他们不可以这样操作:

# 如果想要对一个类的对象进行with  as 的操作 不行。
class A:
    def __init__(self, text):
        self.text = text

with A('大爷') as f1:
    print(f1.text)

有他们可以这样操作

class A:

    def __init__(self, text):
        self.text = text

    def __enter__(self):  # 开启上下文管理器对象时触发此方法
        self.text = self.text + '您来啦'
        return self  # 将实例化的对象返回f1

    def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
        self.text = self.text + '这就走啦'

with A('大爷') as f1:
    print(f1.text)
print(f1.text)
class A:
    def __init__(self, text):
        self.text = text

    def __enter__(self):
        print(1)
        self.text = self.text + "您来了!"
        return self  # 必须要加return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(3)
        self.text = self.text + ", 您要走啦!"

with A("章超印") as f:
    print(2)
    print(f.text)
print(4)
print(f.text)

自定义文件管理器 自己的类需要支持with语句

class Diycontextor:
    def __init__(self, name, mode):
        self.name = name
        self.mode = mode

    def __enter__(self):
       # print("Hi enter here!!")
        self.filehander = open(self.name, self.mode)
        return self.filehander

    def __exit__(self, *para):
        # print("Hi exit here")
        self.filehander.close()

with Diycontextor('周道镕秘密文件', 'r') as f:
    for i in f:
        print(i)

相关面试题:

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def run(self):
        self()

    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StarkConfig):
    def __call__(self, *args, **kwargs):
        print(345)
    def __getitem__(self, item):
        return self.num[item]

v1 = RoleConfig('alex')
v2 = StarkConfig('太白金星')
# print(v1[1])
# print(v2[2])
v1.run()

-------
class UserInfo:
    pass

class Department:
    pass

class StarkConfig:
    def __init__(self, num):
        self.num = num

    def changelist(self, request):
        print(self.num, request)

    def run(self):
        self.changelist(999)

class RoleConfig(StarkConfig):
    def changelist(self, request):
        print(666, self.num)

class AdminSite:

    def __init__(self):
        self._registry = {}

    def register(self, k, v):
        self._registry[k] = v

site = AdminSite()
site.register(UserInfo, StarkConfig)
# 1
# obj = site._registry[UserInfo]()

# 2
obj = site._registry[UserInfo](100)
obj.run()

-------
class UserInfo:
    pass

class Department:
    pass

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def changelist(self,request):
        print(self.num,request)

    def run(self):
        self.changelist(999)

class RoleConfig(StarkConfig):
    def changelist(self,request):
        print(666,self.num)

class AdminSite:

    def __init__(self):
        self._registry = {}

    def register(self,k,v):
        self._registry[k] = v(k)

site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)

for k,row in site._registry.items():
    row.run()

-------
class A:
    list_display = []

    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

s1 = A()
print(s1.get_list())

-------
class A:
    list_display = [1, 2, 3]
    def __init__(self):
        self.list_display = []
    def get_list(self):
        self.list_display.insert(0, 33)
        return self.list_display

s1 = A()
print(s1.get_list())

------
class A:
    list_display = []

    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

class B(A):
    list_display = [11,22]

s1 = A()
s2 = B()
print(s1.get_list())
print(s2.get_list())

百万年薪python之路 -- 面向对象之 反射,双下方法的更多相关文章

  1. Python面向对象之反射,双下方法

    一. 反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...

  2. 百万年薪python之路 -- 面向对象之继承

    面向对象之继承 1.什么是面向对象的继承 继承(英语:inheritance)是面向对象软件技术当中的一个概念. 通俗易懂的理解是:子承父业,合法继承家产 专业的理解是:子类可以完全使用父类的方法和属 ...

  3. 百万年薪python之路 -- 面向对象之三大特性

    1.面向对象之三大特性 1.1封装 封装:就是把一堆代码和数据,放在一个空间,并且可以使用 对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封 ...

  4. 百万年薪python之路 -- 面向对象之:类空间问题以及类之间的关系

    面向对象之:类空间问题以及类之间的关系 1.从空间角度研究类 1.何处添加对象属性 class A: def __init__(self,name): self.name = name def fun ...

  5. 百万年薪python之路 -- 面向对象之所有属性及方法

    1.私有成员公有成员 1.1 类的私有属性 # class A: # # name = '周道镕' # __name = 'zdr' # 私有类的属性 # # def func(self): # pr ...

  6. 百万年薪python之路 -- 面向对象初始

    面向对象初始 1.1 面向过程编程vs函数式编程 函数编程较之面向过程编程最明显的两个特点: 1,减少代码的重用性. 2,增强代码的可读性. 1.2 函数式编程vs面向对象编程 面向对象编程:是一类相 ...

  7. python之面向对象函数与方法,反射,双下方法

    一.函数和方法 1.函数和方法的区别 函数: 全都是显性传参,手动传参,与对象无关 方法: 存在隐性传参,与对象有关 1.1通过函数名可以判断 len()就是函数 str.count()就是方法 de ...

  8. 百万年薪python之路 -- 迭代器

    3.1 可迭代对象 3.1.1 可迭代对象定义 **在python中,但凡内部含有 _ _ iter_ _方法的对象,都是可迭代对象**. 3.1.2 查看对象内部方法 该对象内部含有什么方法除了看源 ...

  9. 百万年薪python之路 -- JS基础介绍及数据类型

    JS代码的引入 方式1: <script> alert('兽人永不为奴!') </script> 方式2:外部文件引入 src属性值为js文件路径 <script src ...

随机推荐

  1. Redis基础(官方文档总结)

    REmote DIctionary Server(Redis) Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供 ...

  2. 转:怎么用Sql语句获取一个数据库中的所有表的名字

    用sql获取数据库中所有的表名的方法:1.oracle下:select table_name from all_tables;2.MySQL下:select table_name from infor ...

  3. 从github下载的vue项目启动宝Cannot Get错误

    从github下载的vue项目启动宝Cannot Get错误,网上参考出现该错误来源很多,这里先总结遇到的第一个解决方法. 参考地址: https://www.cnblogs.com/anns/p/7 ...

  4. .Net Core 商城微服务项目系列(一):使用IdentityServer4构建基础登录验证

    这里第一次搭建,所以IdentityServer端比较简单,后期再进行完善. 1.新建API项目MI.Service.Identity,NuGet引用IdentityServer4,添加类InMemo ...

  5. Stanford公开课《编译原理》学习笔记(2)递归下降法

    目录 一. Parse阶段 CFG Recursive Descent(递归下降遍历) 二. 递归下降遍历 2.1 预备知识 2.2 多行语句的处理思路 2.3 简易的文法定义 2.4 文法产生式的代 ...

  6. linux mint 19.2与Windows 10 双系统硬盘安装与卸载

    安装linux mint 和win10双系统: 1.win10系统下如果没有空闲分区,请从容量较大的分区用partition manager在选中的较大的分区下,调整大小.此步骤最好在pe下的part ...

  7. JDK 1.8 之 Map.merge()

    Map 中ConcurrentHashMap是线程安全的,但不是所有操作都是,例如get()之后再put()就不是了,这时使用merge()确保没有更新会丢失. 因为Map.merge()意味着我们可 ...

  8. 从零开始的vue学习笔记(二)

    数据与方法 当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中.data的数据和视图同步更新. 实例创建后添加一个新的属性,对这个属性的的改动将不会触发任何 ...

  9. Docker 学习笔记之 核心概念

    Docker核心概念: Docker Daemon Docker Container Docker Registry Docker Client 通过rest API 和Docker Daemon进程 ...

  10. VirtualBox 启动时提示“获取 VirtualBox COM 对象失败”的解决

    昨天给电脑打了一堆补丁和更新,今天启动 VirtualBox 的时候提示 “获取 VirtualBox COM 对象失败”,好在百度到了 CSDN 上的一篇文章解决了这个问题. 错误详情 “获取 Vi ...