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

元类type

--在python中,一切皆对象,类也可以理解为“对象”,而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是油type元类创造的

print(type('abc'))
print(type(True))
print(type(100))
print(type([1, 2, 3]))
print(type({'name': '太白金星'}))
print(type((1,2,3)))
​
print(type(object))
​
class A:
    passprint(isinstance(object,type))
print(isinstance(A, type))
print(isinstance(str,type))
  • 而type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类,这就属于鸡生蛋蛋生鸡的关系。

反射

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

--一切皆对象,类本身也是一个对象

四个可以实现自省的函数---hasattr getattr setattr delattr

  • 对实例对象的反射

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')
  • 对其他模块(其他文件)的反射

# test.py 文件
def test():
    print('from the test')
​
# index.py 文件
import test as obj
print(hasattr(obj,'test'))
getattr(obj,'test')()

反射的应用:以前写登录注册等,需要定义一个字典进行匹配,如果使用反射,会使代码更灵活简单

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('输入错误。。。。')

函数和方法区分

1. 函数和方法的区分

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

def func():
    print('func...')
    
print(func)   # <function func at 0x00000260A2E690D0>
class A:
    def func(self):
        print('in A func')
        
print(A.func)    #  <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func)   
#<bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>
  • 通过types模块验证

from types import FunctionType
from types import MethodType
​
def func():
    passclass 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     
  • 静态方法是函数

class A:
    @staticmethod
    def func(self):
        pass
    
obj = A()
# 静态方法其实是函数
print(isinstance(A.func2,FunctionType))  # True
print(isinstance(obj.func2,FunctionType))   # True

2. 函数与方法的区别

  • 函数与方法最显著的区别就是是否为隐形传参,隐形传参的就是方法

双下方法

--双下方法是特殊方法,他是解释器提供的,__方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法

--调用:不同的双下方法,调用的方式也不同

  • __len__

class A:
    def __init__(self):
        self.a = 1
        self.b = 2def __len__(self):
        return len(self.__dict__)   
    # __dict__可查看对象中的属性(字典格式),len之后可以获取对象中字典的个数
a = A()
print(len(a))
  • __hash__

class A:
    def __init__(self):
        self.a = 1
        self.b = 2def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
  • __str__:如果一个类中定义了这个双下方法,那么在打印对象是,默认输出该方法的返回值

class A:
    def __init__(self):
        pass
    def __str__(self):
        return 'lucky'
a = A()
print(a)
print('%s' % a)
  • __repr__:一个类中定义了__repr__,那么在repr(对象)时,默认输出该方法的返回值

class A:
    def __init__(self):
        pass
    def __str__(self):
        return 'lucky'
        
a = A()
print(repr(a))
print('%r'%a)
  • __call__对象后面加(),触发执行

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

class Foo:
​
    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):
​
        print('__call__')
​
​
obj = Foo() # 执行 __init__
obj()       # 执行 __call__
  • __eq__:执行双等判断的时候触发

class A:
    def __init__(self):
        self.a = 1
        self.b = 2def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)
  • __del__:析构方法,当对象在内存中被释放是,自动触发执行

注:这个方法一般不需要定义,因为python解释器会自动执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

  • __new__:在__init__之前调用

注:__new__至少要有一个参数cls,代表要实例化的类,这个参数python解释器自动提供

__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例。

__init__有一个参数self,这个就是__new__返回的实例,__init____new__的基础上可以完成一些其他初始化的动作,__init__不需要返回值

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

 

猜你喜欢

转载自www.cnblogs.com/z-x-h/p/12093705.html