反射,双下方法

一. 反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

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

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

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__)

对实例化对象的示例

对对象的反射

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')

对类的反射

import sys

def s1():
    print 's1'

def s2():
    print 's2'

this_module = sys.modules[__name__]

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

当前模块的反射

#一个模块中的代码
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('输入错误。。。。')

学了反射之后解决方式

有多简单,一目了然。

二. 函数 vs 方法

学到这里,我终于能回答你一直以来可能有的一个疑问。那就是,之前的学习中我们称len()为函数(口误时称为方法)却称如str的strip为方法,那它到底叫什么?函数和方法有什么区别和相同之处?我在这里就正式的解释一下。

2.1 通过打印函数(方法)名确定

def func():
    pass

print(func)  # <function func at 0x00000260A2E690D0>

class A:
    def func(self):
        pass

print(A.func)  # <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func)  # <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>

View Code

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

View Code

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

View Code

2.4 函数与方法的区别

那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。

(1)函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。

(2)函数则跟对象无关。

(3)方法中的数据则是隐式传递的。

(4)方法可以操作类内部的数据。

(5)方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。

我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。

在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中。

三. 双下方法

定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:init

3.01 __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))

View Code

3.02 __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))

View Code

3.03 str

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

class A:
    def __init__(self):
        pass
    def __str__(self):
        return '太白'
a = A()
print(a)
print('%s' % a)

View Code

3.04 repr

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

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

View Code

3.05 call

对象后面加括号,触发执行。

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

class Foo:

    def __init__(self):
        pass

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

        print('__call__')

obj = Foo() # 执行 __init__
obj()       # 执行 __call__

View Code

3.06 __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)

View Code

3.07 del

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

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

3.08__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)

View Code

class A:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

单例模式

单例模式具体分析

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

3.09 __item__系列

class Foo:
    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)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)

View Code

3.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 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('py_ana.py','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())

View Code

(0)

相关推荐

  • Python中的多态如何理解?

    Python中多态的作用 让具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容(功能)的函数. Python中多态的特点 1.只关心对象的实例方法是否同名,不关心对象所属的类型 ...

  • 【Python核心编程笔记】一、Python中一切皆对象

    Python中一切皆对象 本章节首先对比静态语言以及动态语言,然后介绍 python 中最底层也是面向对象最重要的几个概念-object.type和class之间的关系,以此来引出在python如何做 ...

  • 说说Python中的__new__和__init__的区别?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • 温故而知新--day2

    温故而知新--day2 类 类与对象 类是一个抽象的概念,是指对现实生活中一类具有共同特征的事物的抽象.其实列化后称为对象.类里面由类属性组成,类属性可以分为数据属性和函数属性(函数属性又称为类方法) ...

  • Python语言学习之双下划线那些事:python和双下划线使用方法之详细攻略

    Python语言学习之双下划线那些事:python和双下划线使用方法之详细攻略 双下划线介绍 1.关于双下划线的函数或方法或属性 __name__:前后加了双下划线是因为是因为这是系统定义的名字.普通 ...

  • 原创|最简单最快的双系统安装方法

    有不少朋友在微信公众号中问我怎么安装WINDOWS双系统,那今天就来讲讲我最常用的安装方法.在我还没学会怎么安装之前,也觉得能够在电脑上装两个系统甚至三四个系统是件了不起的事情,直到自己也学会后才发觉 ...

  • 想要做家务也有运动的效果,注意下方法哦

    糖友知道做家务不能代替运动,但是只要注意方法也能做出健身效果来的. 扫地.拖地 很多人觉得扫地.拖地这样的清扫家务事既繁琐又无趣,但是假如把它们看成是减肥的运动,也许你会很乐意去做. 拖地是中等体力劳 ...

  • 1楼:反对装电梯,6楼:有个双赢方法

    1楼:反对装电梯,6楼:有个双赢方法

  • 鉴别宣德炉的真伪下方法

    宣德炉最妙在色,其色内融,从黯淡中发奇光.史料记载有四十多种色泽,为世人钟爱,其色的名称很多.例如,紫带青黑似茄皮的,叫茄皮色;黑黄象藏经纸的,叫藏经色;黑白带红淡黄 色的,叫褐色;如旧玉之土沁色的, ...

  • 鉴别舍利子的真伪下方法

    相传2500年前佛祖释迦牟尼涅槃后,弟 子们依照嘱托,架起香木焚化佛陀遗体,弟 子们在火化他的遗体时从灰烬中得到了一块头顶骨.两块肩胛骨.四颗牙齿.一节中指指骨,这些都被称佛舍利.另外还有许多五色珍珠 ...

  • 鉴别洪武通宝一两的真伪下方法

    "一眼".看到图片后,大致扫一下.如果是一些地摊级别的仿品(例如非银金属仿品,早期边齿非常经典的银质仿品).这些仿品往往银色不对,边齿是非常经典的直齿,文字图案也和真品有区别这类通 ...

  • Excel如何给文字添加双下划线?

    Excel中对文字的编辑和Word比较类似,但又不完全一致,今天小编就来教大家如何 给文字添加双下划线吧!不过使用频率并不是很高,大家仅供了解即可. 1.打开一个空白的Excel表格,按住Ctrl键转 ...

  • 鉴别鸡血石的真伪下方法

    我国最早被发现的鸡血石,位于浙江昌化的玉岩山,故又称昌化鸡血石.后来在内蒙古赤峰的巴林右旗也有发现,为便与区分,称为巴林鸡血石.目前,我国四川.广西等地也有少量其他品种的鸡血石矿采.自最早的昌化鸡血石 ...