2014-01-16 67 views
2

考慮:如何確定在方法中引用哪些自我屬性?

class A(object): 
    def m(self): 
    print self.x + self.y + self.z() 

有沒有一種方法來查詢:

self_attributes_referenced(A.m) #=> ['x', 'y'] 

沒有做反編譯或解析?

是否有相應的方法來調用自我方法?

self_methods_referenced(A.m) #=> ['z'] 
+0

我來使用''dis''模塊最接近的一次。但是,這將需要一些我沒有時間的輸出解析:/ –

+0

目前尚不清楚你正在嘗試做什麼。您是否試圖找到一種方法來查看屬性是否已設置/使用/查看,並且方法相同?或者是其他東西? – Aidan

+0

這似乎是一件奇怪的事情想要做。首先,它通過一個你通常不應該嘲笑的抽象障礙。另一方面,它不會像你期望的那樣告訴你。考慮'def method(self):return self .__ helper_that_does_all_the_work()'。誰知道這是什麼? – user2357112

回答

1

像這樣的東西應該工作:

import inspect 


class Referee(object): 
    def __getattribute__(self, name): 
     attr = object.__getattribute__(self, name) 
     if inspect.ismethod(attr): 
      try: 
       meths_referenced = object.__getattribute__(
        self, 'meths_referenced') 
      except AttributeError: 
       meths_referenced = set() 
       object.__setattr__(self, 'meths_referenced', meths_referenced) 

      meths_referenced.add(name) 
     else: 
      try: 
       attrs_referenced = object.__getattribute__(
        self, 'attrs_referenced') 
      except AttributeError: 
       attrs_referenced = set() 
       object.__setattr__(self, 'attrs_referenced', attrs_referenced) 

      attrs_referenced.add(name) 

     return attr 


def attributes_referenced(obj): 
    try: 
     return object.__getattribute__(obj, 'attrs_referenced') 
    except AttributeError: 
     return set() 


def methods_referenced(obj): 
    try: 
     return object.__getattribute__(obj, 'meths_referenced') 
    except AttributeError: 
     return set() 


class A(Referee): 
    def __init__(self): 
     self.x = 1 
     self.y = 2 

    def z(self): 
     return 3 

    def m(self): 
     print self.x + self.y + self.z() 


a = A() 
a.m() 
print attributes_referenced(a) 
print methods_referenced(a) 

此打印:

6 
set(['y', 'x']) 
set(['z', 'm']) 

繼承Referee,每當你想提供此功能。 爲什麼你需要這個功能超出了我的理解。 =)

+0

這可能是我見過的最痛苦的事情。感謝你擁有意志力,甚至寫下它。 –

1

在這個問題中,您將解析排除爲解決方案,但您是否意識到使用ast module解析和修改Python源代碼是多麼容易?

首先定義一個NodeTransformer

import ast 

class RecordReferencesTransformer(ast.NodeTransformer): 
    def visit_FunctionDef(self, node): 
     def is_attr_on_self(n): 
      return type(n) is ast.Attribute and type(n.value) is ast.Name and n.value.id == 'self' 

     targets = [ast.Attribute(value=ast.Name(id=node.name, ctx=ast.Load()), attr='self_attributes_referenced', ctx=ast.Store())] 
     attrs = [n.attr for n in ast.walk(node) if is_attr_on_self(n)] 
     value = ast.Tuple(elts=[ast.Str(s=attr) for attr in attrs], ctx=ast.Load()) 
     return [node, ast.Assign(targets=targets, value=value)] 

然後而不是直接使用import加載我們的模塊,我們需要一點額外的樣板在我們NodeTransformer勻場:

filename = 'program.py' 
parsed = ast.parse(open(filename).read()) 
with_references = RecordReferencesTransformer().visit(parsed) 
ast.fix_missing_locations(with_references) 
exec compile(with_references, filename, 'exec') 

print A.m.self_attributes_referenced 
a = A() 
a.m() 

輸出:

('x', 'y') 
3 

實施self_methods_referenced作爲練習留給讀者。

最後,program.py來源:

class A(object): 
    x, y = 1, 2 
    def m(self): 
     print self.x + self.y 
+0

真不可思議。你甚至不需要**運行** A()和a.m()。 「打印A.m.self_attributes_referenced」就足夠了。 –

+1

@ A.JesseJiryuDavis true!我重新安排了陳述以說明這一點 –

相關問題