Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 检测uuu getattribute_uuuu调用是否是由于hasattr引起的_Python_Getattribute_Hasattr - Fatal编程技术网

Python 检测uuu getattribute_uuuu调用是否是由于hasattr引起的

Python 检测uuu getattribute_uuuu调用是否是由于hasattr引起的,python,getattribute,hasattr,Python,Getattribute,Hasattr,我正在为一个类实现\uuu getattribute\uuu 我想指出任何不正确的(当然,这意味着可能会失败)提供属性的失败(因为\uuuu getattribute\uuuu实现非常复杂)。因此,如果我的代码在引发AttributeError之前无法找到/提供属性,我会记录一条警告 我知道: \uuuu getattribute\uuuu鼓励实现尽可能小而简单 根据调用方式/原因,\uuuu getattribute\uuu实现的行为不同,这被认为是错误的 访问属性的代码也可以尝试/excep

我正在为一个类实现
\uuu getattribute\uuu

我想指出任何不正确的(当然,这意味着可能会失败)提供属性的失败(因为
\uuuu getattribute\uuuu
实现非常复杂)。因此,如果我的代码在引发
AttributeError
之前无法找到/提供属性,我会记录一条警告

我知道:

  • \uuuu getattribute\uuuu
    鼓励实现尽可能小而简单
  • 根据调用方式/原因,
    \uuuu getattribute\uuu
    实现的行为不同,这被认为是错误的
  • 访问属性的代码也可以尝试/except而不是使用hasattr

  • TL;DR:尽管如此,我还是想检测对
    \uu getattribute\uuu
    的调用是否是由于
    hasattr
    (与访问属性的“真实”尝试相反)。

    您可以使用
    sys.\u getframe
    获取调用方帧,并使用
    inspect.getframeinfo
    获取进行调用的代码行,然后使用某种解析机制,比如regex(不能使用
    ast.parse
    ,因为一行代码通常是不完整的语句),查看
    hasattr
    是否是调用方。它不是很健壮,但在最合理的情况下应该可以工作:

    import inspect
    import sys
    import re
    class A:
        def __getattribute__(self, item):
            if re.search(r'\bhasattr\b', inspect.getframeinfo(sys._getframe(1)).code_context[0]):
                print('called by hasattr')
            else:
                print('called by something else')
    hasattr(A(), 'foo')
    getattr(A(), 'foo')
    
    这将产生:

    called by hasattr
    called by something else
    

    即使通过烟囱检查,这也是不可能的<代码> HASTART 在Python调用堆栈中不生成框架对象,因为它是用C编写的,并且试图检查最后一个Python帧,以猜测它是否被挂在“代码”> HASTART的中间,调用容易出现各种假阴性和假阳性。 如果你下定决心要尽最大努力,那么我能想到的最可靠(但仍然很脆弱)的方法就是使用一个Python函数来生成Python堆栈框架,即monkey patch
    builtins.hasattr

    import builtins
    import inspect
    import types
    
    _builtin_hasattr = builtins.hasattr
    if not isinstance(_builtin_hasattr, types.BuiltinFunctionType):
        raise Exception('hasattr already patched by someone else!')
    
    def hasattr(obj, name):
        return _builtin_hasattr(obj, name)
    
    builtins.hasattr = hasattr
    
    def probably_called_from_hasattr():
        # Caller's caller's frame.
        frame = inspect.currentframe().f_back.f_back
        return frame.f_code is hasattr.__code__
    
    调用
    可能是从
    内部的\u hasattr
    调用的\u然后将测试您的
    可能是从
    hasattr
    调用的。这避免了假设调用代码使用名称“hasattr”,或者使用名称“hasattr”对应于这个特定的
    \uuu getattribute\uuuu
    调用,或者
    hasattr
    调用源自Python级别的代码而不是C

    这里脆弱性的主要来源是,如果有人在monkey补丁运行之前保存了对real
    hasattr
    的引用,或者其他人在monkey补丁运行之前保存了对real
    hasattr
    的引用(例如,如果有人将此代码复制粘贴到同一程序中的另一个文件中)。
    isinstance
    check试图捕捉我们面前的大多数其他猴子补丁案例
    hasattr
    ,但它并不完美

    此外,如果用C编写的对象上的
    hasattr
    触发了对对象的属性访问,则这看起来像是从
    hasattr
    调用了您的
    \uuu getattribute\uuuuuu
    。这是获得假阳性的最有可能的方法;上一段中的所有内容都会给出错误的否定。您可以通过检查
    hasattr
    frame的
    f_locals
    中的
    obj
    条目是否是它应该是的对象来防止出现这种情况


    最后,如果您的
    \uuuuuu getattribute\uuuuuuuu
    是从装饰程序创建的包装、子类
    \uuuuuuuuuu getattribute\uuuuuuuuuuuuuuuuu
    调用的,那么即使从
    hasaattr
    调用了包装或重写,也不算是从
    hasaattr
    调用的,即使你想让它计数。

    这在很多合理的情况下都会失败,例如
    如果hasattr(thing,'existing_attribute')和thing.existing_attribute==5
    如果hasattr(different_thing,'foo')或thing_with_getattribute.bar==5
    。谢谢你的回答!我已经考虑过做一些类似的事情,但是分析这句话容易出错。我希望找到更具容错性,或者至少具有较少误报的功能(即,我可以接受缺少的基于
    hasattr
    的调用,但不会错过“真正的”调用)。@user2357112是的,但如果一个人确实需要某个属性的值,那么他/她首先就不应该使用
    hasattr
    ,而是使用带有默认值的
    getattr
    ,或者使用
    try
    阻塞
    对象。现有的\u属性
    ,以避免对
    \uu getattribute
    的冗余和潜在危险的调用(当存在多个线程时)。如果只关心属性的存在,而不关心属性的值,则只能使用
    hasattr
    。如果程序员遵循这一原则,那么我的方法的缺陷就不会成为问题。这个问题的前提是询问如何做违反设计原则的事情。假设代码库的其余部分严格遵循任何特定原则似乎是不安全的。另外,当您需要能够区分属性缺失和碰巧是默认值的属性值时,使用默认值的
    getattr
    会很尴尬,即使在遵循您列出的规则的情况下,这仍然会失败。谢谢!覆盖hasattr确实是一个简单的解决方案。我自己应该想到的!