python反射

阅读目录

 

isinstance和issubclass

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

class Foo(object):
     pass
  
obj = Foo()
  
sinstance(obj, Foo)

issubclass(sub, super)检查sub类是否是 super 类的派生类 

复制代码
class Foo(object):
    pass
 
class Bar(Foo):
    pass
 
issubclass(Bar, Foo)
复制代码

 

反射

1 什么是反射

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

 

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

四个可以实现自省的函数

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

hasattr

def hasattr(*args, **kwargs): # real signature unknown
    """
    Return whether the object has an attribute with the given name.
    
    This is done by calling getattr(obj, name) and catching AttributeError.
    """
    pass
getattr

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass
setattr

def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    
    setattr(x, 'y', v) is equivalent to ``x.y = v''
    """
    pass
delattr

def delattr(x, y): # real signature unknown; restored from __doc__
    """
    Deletes the named attribute from the given object.
    
    delattr(x, 'y') is equivalent to ``del x.y''
    """
    pass
四个方法的使用演示

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')
反射当前模块成员

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
#!/usr/bin/env python
# -*- coding:utf-8 -*-

def test():
    print('from the test')
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
"""
程序目录:
    module_test.py
    index.py
 
当前文件:
    index.py
"""

import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

__str__和__repr__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

#_*_coding:utf-8_*_

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))
%s和%r

class B:

     def __str__(self):
         return 'str : class B'

     def __repr__(self):
         return 'repr : class B'

b=B()
print('%s'%b)
print('%r'%b)

__del__

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

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

 简单示范

class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
del f1
print('------->')

#输出结果
执行我啦
------->

item系列

__getitem__\__setitem__\__delitem__
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__)

__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 Singleton:
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

one = Singleton()
two = Singleton()

two.a = 3
print(one.a)
# 3
# one和two完全相同,可以用id(), ==, is检测
print(id(one))
# 29097904
print(id(two))
# 29097904
print(one == two)
# True
print(one is two)

__call__

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

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

class Foo:

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

        print('__call__')


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

__len__

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

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))

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

__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)
纸牌游戏
class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    suits = ['红心','方板','梅花','黑桃']

    def __init__(self):
        self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
                                        for suit in FranchDeck.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))
纸牌游戏2
class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    suits = ['红心','方板','梅花','黑桃']

    def __init__(self):
        self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
                                        for suit in FranchDeck.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

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

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))

from random import shuffle
shuffle(deck)
print(deck[:5])
一道面试题
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def __hash__(self):
        return hash(self.name+self.sex)

    def __eq__(self, other):
        if self.name == other.name and self.sex == other.sex:return True


p_lst = []
for i in range(84):
    p_lst.append(Person('egon',i,'male'))

print(p_lst)
print(set(p_lst))

 

转载于:https://www.cnblogs.com/caoxing2017/p/7391467.html

<think>好的,用户想了解Python中的反射机制或者如何使用反射。我需要先回顾一下反射的基本概念,然后结合用户提供的引用资料来组织回答。首先,反射的定义是什么?根据引用1,反射是程序运行时动态访问、检查和修改其状态或行为的能力。在Python中,这通常涉及操作对象的属性、方法和类信息。引用3提到四个关键函数:hasattr、getattr、setattr和delattr,这些应该是核心内容。接下来,我需要解释反射的作用和应用场景。引用4指出反射在框架开发、动态模块加载和测试中的便利性,这部分可以作为应用场景的例子。同时,用户可能需要具体的代码示例来理解如何使用这些函数。例如,使用getattr动态调用方法,或者用setattr设置属性。还要注意用户可能关心的注意事项,比如性能开销和可读性问题,引用4提到这一点,需要提醒用户适度使用。此外,引用2和引用3提供的链接可以作为扩展阅读,但用户可能不需要这些,所以保持回答简洁。然后,按照用户的要求,生成相关问题。问题应该围绕反射机制展开,比如如何动态导入模块、反射的安全性问题、与其它语言的对比,以及实际项目中的应用案例。最后,确保回答结构清晰,分点说明,每个部分有代码示例,并自然添加引用标识。需要检查LaTeX格式是否正确,不过用户的问题中没有数学公式,所以可能不需要处理这部分。但系统指令要求行内数学表达式用$...$,所以如果有的话要注意,但这里可能不涉及。</think>### Python反射机制详解 反射机制允许程序在运行时动态操作对象的属性和方法。以下是核心概念和使用方法: #### 一、反射的四大核心函数 1. **检查属性是否存在** 使用$hasattr(obj, 'attribute_name')$检查对象是否包含指定属性或方法[^3] ```python class MyClass: def my_method(self): print("Hello") obj = MyClass() print(hasattr(obj, 'my_method')) # True ``` 2. **获取属性值/方法** 通过$getattr(obj, 'attribute_name'[, default])$动态获取属性值或方法引用[^3] ```python method = getattr(obj, 'my_method', None) if method: method() # 输出 Hello ``` 3. **动态设置属性** $setattr(obj, 'new_attribute', value)$可为对象添加新属性[^3] ```python setattr(obj, 'dynamic_value', 42) print(obj.dynamic_value) # 42 ``` 4. **删除属性** $delattr(obj, 'attribute_name')$可移除对象的指定属性[^3] ```python delattr(obj, 'dynamic_value') ``` #### 二、典型应用场景 1. **插件系统开发** 动态加载模块并检查是否存在指定接口[^4]: ```python import importlib plugin = importlib.import_module('my_plugin') if hasattr(plugin, 'execute'): getattr(plugin, 'execute')() ``` 2. **Web框架路由映射** 自动将URL路径映射到控制器方法[^2]: ```python class UserController: def list_users(self): return "User list" action = request.path.split('/')[-1] if hasattr(UserController(), action): return getattr(UserController(), action)() ``` 3. **配置驱动开发** 根据配置文件动态调用方法[^1]: ```python config = {'operation': 'encrypt', 'algorithm': 'AES'} crypto = CryptoHandler() method_name = f"{config['operation']}_using_{config['algorithm']}" if hasattr(crypto, method_name): getattr(crypto, method_name)(data) ``` #### 三、注意事项 1. **类型安全**:动态获取的属性需进行类型校验 2. **性能影响**:反射操作比直接调用慢约$20\%-30\%$[^4] 3. **命名规范**:建议使用下划线命名法保持属性可预测性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值