【问题标题】:How would you determine where each property and method of a Python class is defined?您如何确定 Python 类的每个属性和方法的定义位置?
【发布时间】:2010-10-03 20:22:27
【问题描述】:

给定 Python 中某个类的实例,能够确定每个方法和属性定义的源代码行(例如,实现1)会很有用。例如,给定一个模块 ab.py

class A(object):
    z = 1
    q = 2
    def y(self): pass
    def x(self): pass

class B(A):
    q = 4
    def x(self): pass
    def w(self): pass

定义一个函数 where(class_, attribute) 返回一个元组,该元组包含源代码中定义或子类化attribute 的文件名、类和行。这意味着在班级主体中的定义,而不是由于过度活跃而导致的最新分配。如果它为某些属性返回“未知”,那很好。

>>> a = A()
>>> b = B()
>>> b.spigot = 'brass'
>>> whither(a, 'z')
("ab.py", <class 'a.A'>, [line] 2)
>>> whither(b,  'q')
("ab.py", <class 'a.B'>, 8)
>>> whither(b, 'x')
("ab.py", <class 'a.B'>, 9)
>>> whither(b, 'spigot')
("Attribute 'spigot' is a data attribute")

我想在自省 Plone 时使用它,其中每个对象都有数百个方法,按类而不是按字母顺序对它们进行排序非常有用。

当然,在 Python 中你不能总是合理地知道,但在大多数静态代码的常见情况下获得好的答案会很好。

【问题讨论】:

    标签: python introspection plone python-datamodel


    【解决方案1】:

    您正在寻找未记录的函数inspect.classify_class_attrs(cls)。传递一个类,它将返回一个元组列表('name', 'kind' e.g. 'method' or 'data', defining class, property)。如果您需要有关特定实例中绝对所有内容的信息,则必须做额外的工作。

    例子:

    >>> import inspect
    >>> import pprint
    >>> import calendar
    >>> 
    >>> hc = calendar.HTMLCalendar()
    >>> hc.__class__.pathos = None
    >>> calendar.Calendar.phobos = None
    >>> pprint.pprint(inspect.classify_class_attrs(hc.__class__))
    [...
     ('__doc__',
      'data',
      <class 'calendar.HTMLCalendar'>,
      '\n    This calendar returns complete HTML pages.\n    '),
     ...
     ('__new__',
      'data',
      <type 'object'>,
      <built-in method __new__ of type object at 0x814fac0>),
     ...
     ('cssclasses',
      'data',
      <class 'calendar.HTMLCalendar'>,
      ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']),
     ('firstweekday',
      'property',
      <class 'calendar.Calendar'>,
      <property object at 0x98b8c34>),
     ('formatday',
      'method',
      <class 'calendar.HTMLCalendar'>,
      <function formatday at 0x98b7bc4>),
     ...
     ('pathos', 'data', <class 'calendar.HTMLCalendar'>, None),
     ('phobos', 'data', <class 'calendar.Calendar'>, None),
     ...
     ]
    

    【讨论】:

    • 您的意思是回答您自己的问题吗?
    • 我试图避免回答我自己的问题,但由于我得到的 2 个相关 SO 问题的答案都不是我想要的,我别无选择,只能深入挖掘并找到它我自己。
    【解决方案2】:

    您正在寻找inspect 模块,特别是inspect.getsourcefile()inspect.getsourcelines()。例如

    a.py:

    class Hello(object):
        def say(self):
           print 1
    
    >>> from a import Hello
    >>> hi = Hello()
    >>> inspect.getsourcefile(hi.say)
    a.py
    >>> inspect.getsourcelines(A, foo)
    (['   def say(self):\n        print 1\n'], 2)
    

    鉴于 Python 的动态特性,在更复杂的情况下这样做可能根本不可能......

    【讨论】:

    • inspect.getmembers(portal) >>> AttributeError: index_html 虽然,inspect.getmembers(portal.__class__) 有效...
    【解决方案3】:

    如果没有静态分析,这或多或少是不可能的,即使那样,它也不会总是有效。您可以通过检查其代码对象来获取定义函数的行以及在哪个文件中,但除此之外,您无能为力。 inspect 模块可以帮助解决这个问题。所以:

    import ab
    a = ab.A()
    meth = a.x
    # So, now we have the method.
    func = meth.im_func
    # And the function from the method.
    code = func.func_code
    # And the code from the function!
    print code.co_firstlineno, code.co_filename
    
    # Or:
    import inspect
    print inspect.getsource(meth), inspect.getfile(meth)
    

    但是考虑一下:

    def some_method(self):
        pass
    ab.A.some_method = some_method
    ab.A.some_class_attribute = None
    

    或者更糟:

    some_cls = ab.A
    some_string_var = 'another_instance_attribute'
    setattr(some_cls, some_string_var, None)
    

    尤其是在后一种情况下,您想要或期望得到什么?

    【讨论】:

    • -1。当然我知道做一个完美的工作真的很难,但是 inspect.classify_class_attrs(cls) 非常接近。拿那个 S.Lott.,反对者。
    • @Daniel:无法跟踪分配的位置。获得所需信息的唯一方法是将检查模块中的内容与方法或函数一起使用。任意属性只能通过静态分析进行跟踪。
    • @Aaron:当我说“定义”时,我的意思是定义 def 方法():通过,而不是像 ab.A.some_method = 方法中的“分配”。即使对于您的 some_string_var 示例,您也可以知道它是 A 的一部分,而不是超类或子类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    • 2011-11-02
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多