面向对象 反射 和item系列和内置函数和__getattr__和__setattr__

 反射

反射主要用在网络编程中,

python面向对象的反射:通过字符串的形式操作对象相关的属性.python的一切事物都是对象.

反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!

getattr()

查找getattr(object,name[,default]):使用字符串数据类型获取对象的方法和属性,注意name是字符串,如果存在则返回,不存在则打印出默认值,默认值可选。需要注意的是如果要运行这个对象的方法,则需要加括号。

class Manegeemnt:
    def __init__(self,name,sex,phone,mail):
        self.name=name
        self.sex=sex
        self.phone=phone
        self.mail=mail

    def creat_class(self):
        print("创建了一条班级信息")

maneger=Manegeemnt("小雨","","13813216396","xiaoyu@163.com")
func=getattr(maneger,"name") #使用字符串的数据类型的变量名获取属性值。
print(func)

func=getattr(maneger,"creat_class")#得到的是方法的内存地址
func()
func=getattr(maneger,"mails","没有这条信息")
print(func)
 
 

结果:

小雨
创建了一条班级信息
没有这条信息

hasattr()

检查 hasattr(object,name[,default]):判断类中是否有这个属性如果存在返回True,否则False,在进行getattr前先判断有没有这个属性。一般他俩配合着使用。不要用try来替换它,我们能尽量少用try就少用,

多用些代码的方式来解决异常处理。

class Manegeemnt:
    def __init__(self,name,sex,phone,mail):
        self.name=name
        self.sex=sex
        self.phone=phone
        self.mail=mail

    def creat_class(self):
        print("创建了一条班级信息")
import logging
maneger=Manegeemnt("小雨","","13813216396","xiaoyu@163.com")
if hasattr(maneger,"sex1"):
    func=getattr(maneger,"sex1")
    print(func)
else:
    logging.warning("没有这条信息")

结果:

WARNING:root:没有这条信息

setattr()

设置 setattr(obj,变量名,值):对对象设置属性,添加属性。还可以添加方法不过这个方法不常用,

class A:
    age=18
    def __init__(self,name):
        self.name=name
    def walk(self):
        print("walking")
a=A("小明")

setattr(a,"country","中国")
print(a.country)

结果:

中国

 

delattr()

删除 delattr(obj,变量名)

class Manegeemnt:
    def __init__(self,name,sex,phone,mail):
        self.name=name
        self.sex=sex
        self.phone=phone
        self.mail=mail

    def creat_class(self):
        print("创建了一条班级信息")
import logging
maneger=Manegeemnt("小雨","","13813216396","xiaoyu@163.com")

setattr(Manegeemnt,"country","china")
print(Manegeemnt.country)

结果:

china

在sys.modules 里,如果我要运行当前的模块,那么当前的模块的名字就是__main__,所以可以跟筠模块名在sys.modules中得到他的模块对象、

a="bbb"
import sys
y=getattr(sys.modules["__main__"],"a") #利用模块名得到模块对象,注意在sys.modules 中的键是模块名,键值是模块对象。
print(y)

结果

bbb

另一种情况,如果我把上边的这个代码,剪贴到另外一个模块中,然后从本模块中导入,这时候再运行就会出错了,因为当前运行的程序名字中没有这段代码了,就不能用__main__,了,应该改为__name__.

范例:

a="bbb"
import sys
y=getattr(sys.modules[__name__],"a") #注意这里的__name__不能加引号,就是不能写成字符串,它的意思就是代表了这个程序的文件名。
print(y)

 模块的反射

demo.py

def demo():
    print("这是demo模块中的demo函数")

main.py

import demo
ret=getattr(demo,"demo")
ret()

 应用场景:在django的CBV的源码中,在请求到了dispatch方法中是,基于反射根据请求方式的不同去调用不同的请求方法(比如post,get,put)

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

 

 

item系列

__setitem__  ,
__getitem__
__delitem__

在类中, 只能用字典的方式,赋值,取值,删除值,才会调用响应的函数,用类自己的方法来,赋值,取值,删除值,不生效.

 

class A:
    def __init__(self):
        print("init.....")
    def __setitem__(self, key, value):
        print("set....")
    def __getitem__(self, item):
        print("get....")
    def __delitem__(self, key):
        print("del....")
b=A() #调用init函数
b["f"]=3 #调用set函数
b["f"] #调用get函数
del b["f"] #调用delete函数

结果:

init.....
set....
get....
del....

范例二:

lass testsetandget:
    kk = {}
    def __getitem__(self, key):
        return self.kk[key]

    def __setitem__(self, key, value):
        self.kk[key] = value
        print("1111")
a=testsetandget()
a["first"]=1
print(a.kk)
a.__setitem__("你好",2)
a.__getitem__("你好")

结果:

1111
{'first': 1}
1111

 面向对象内置函数

1. issubclass(子类,父类) 判断一个类是不是另一个类的父类

class A:
    pass
class B(A):
    pass

print(issubclass(B,A))

结果:

True

2.isinstance(对象,已知类型) ,判断这个对象是不是已知类型

范例一:判断这个对象是不是A类实例化出来

class A:
    pass
class B(A):
    pass
c=B()
print(isinstance(c,A))

结果:

True

 范例二判断这个变量是不是字符串?

f="fdfd"
print(isinstance(f,str))

结果:

True

 

__getattr__和__setattr__

__getattr__(self,item)

__getattr__(self,item) :拦截点号运算。当对象(注意不能是类,类会报错)对未定义的属性名称(只能是属性不能是方法,虽然调用方法时会调用该方法,但是程序也会报错)点号运算时,就会用属性名作为字符串调用这个方法,其中item就是调用的属性名称字符串。如果继承树可以找到该属性,则不调用此方法

class Foo:
    def __init__(self,name):
        self.name=name
    def __getattr__(self, item):
        print("item",item)
        print("你好啊")
a=Foo("xiao")
a.age

结果:

item age
你好啊

其实这个方法是在看restfromwork中的源码中看到的

#a在APIview中这样调用的, 
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

#但是在APISettings类中并没有这个DEFAULT_AUTHENTICATION_CLASSES属性
class APISettings(object):

    def __getattr__(self, attr):
        if attr not in self.defaults:
            raise AttributeError("Invalid API setting: '%s'" % attr)

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:
            val = perform_import(val, attr)

        # Cache the result
        self._cached_attrs.add(attr)
        setattr(self, attr, val)
        return val

应用场景:

rest_framework中的认证组件中在导入默认认证类的时候出现。

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

就调用了__getattr__

 def __getattr__(self, attr):
        if attr not in self.defaults:
            raise AttributeError("Invalid API setting: '%s'" % attr)

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:
            val = perform_import(val, attr)

        # Cache the result
        self._cached_attrs.add(attr)
        setattr(self, attr, val)
        return val

 

__setattr__()

如果类自定义了__setattr__方法,当通过对实例化赋值时,就会调用__setattr__
常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典__dict__中。

class ClassA(object):
    def __init__(self, classname):
        self.classname = classname

    def __setattr__(self, name, value):
        # self.name = value  # 如果还这样调用会出现无限递归的情况
        print('invoke __setattr__')

insA = ClassA('ClassA') # __init__中的self.classname调用__setattr__。
# invoke __setattr__

insA.tag = 'insA'
# invoke __setattr__

结果:

invoke __setattr__
invoke __setattr__

 

转载于:https://www.cnblogs.com/sticker0726/p/7892236.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值