簡體   English   中英

如何在Python中查找裝飾方法的包含類

[英]How to find the containing class of a decorated method in Python

我正在嘗試實現一個裝飾器類,它將裝飾其他類中的方法。 但是,我需要在裝飾器中保存裝飾方法的類。 我似乎無法在任何地方找到它。

這是一個例子:

class my_decorator(object):

  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_callable):
    print(self.__class__.__name__ + ".__call__")
    print(type(my_callable))
    self.my_callable = my_callable
#    self.my_callable_method_class = ?where to get this?

    def function_wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".function_wrapper")
      print(self.arg1)
      self.my_callable.__call__(*args, **kwargs)
      print(self.arg2)

    return function_wrapper


class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):
    print(self.__class__.__name__ + ".decorated_method")
    print(type(self.decorated_method))
    print("hello")


m = MyClass()
m.decorated_method()

這將打印出來:

my_decorator.__init__
my_decorator.__call__
<type 'function'>
my_decorator.function_wrapper
one
MyClass.decorated_method
<type 'instancemethod'>
hello
two

在decorator類中,callable的類型為function,而在類本身內,它的類型為instancemethod。 我可以從instancemethod獲取im_class,但是函數中沒有這樣的東西。

如何從裝飾器中獲取包含裝飾方法的類?

我能做到這一點:

class my_decorator(object):

  def __init__(self, cls, arg1, arg2):

.
.

class MyClass(object):

  @my_decorator(cls=MyClass, arg1="one", arg2="two")
  def decorated_method(self):

.
.

但我不想這樣做,因為它多余而且不好。

或者我應該以其他方式實現這一點? 我基本上需要一些裝飾器的參數,我需要裝飾器中的裝飾方法的類。

你可以裝飾這個

@decorate
class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):

並使用外部裝飾器將類參數發送到內部。


您的提案都不起作用,因為它們需要在類存在之前訪問該類。 定義類時,首先在其主體內部執行代碼(定義函數等),然后將結果范圍分配給類__dict__ 所以在定義decorated_methodMyClass還不存在。

這是一個有效的修訂版本。

# This holds all called method_decorators
global_method_decorator_list = []

class class_decorator(object):
  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_class):
    print(self.__class__.__name__ + ".__call__")
    print(repr(my_class))
    print(my_class.__name__)
    self.cls = my_class
    class_decorators[my_class] = self
    self.my_class = my_class

    # Call each method decorator's second_init()
    for d in global_method_decorator_list:
      d._method_decorator_.second_init(self, my_class)

    def wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".wrapper")
      print(self.arg1)
      retval = self.my_class.__call__(*args, **kwargs)
      print(self.arg2)
      return retval

    return wrapper


class method_decorator(object):
  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_callable):
    print(self.__class__.__name__ + ".__call__")
    print(repr(my_callable))
    self.my_callable = my_callable

    # Mark the callable and add to global list
    my_callable._method_decorator_ = self
    global_method_decorator_list.append(my_callable)

    def wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".wrapper")
      print(self.arg1)
      retval=self.my_callable.__call__(*args, **kwargs)
      print(self.arg2)
      return retval

    return wrapper

  def second_init(self, the_class_decorator, the_class):
    print(self.__class__.__name__ + ".second_init")
    print("The Class: " + repr(the_class))**


@class_decorator(arg1="One", arg2="Two")
class MyClass(object):

  @method_decorator(arg1="one", arg2="two")
  def decorated_method(self):
    print(self.__class__.__name__ + ".decorated_method")
    print(type(self.decorated_method))
    print("hello")


m = MyClass()
m.decorated_method()

輸出如下所示:

class_decorator.__init__
method_decorator.__init__
method_decorator.__call__
<function decorated_method at 0x3063500>
class_decorator.__call__
<class '__main__.MyClass'>
MyClass
method_decorator.second_init
The Class: <class '__main__.MyClass'>
class_decorator.wrapper
One
Two
method_decorator.wrapper
one
MyClass.decorated_method
<type 'instancemethod'>
hello
two

不同的是,現在有一個單獨的裝飾器。 類裝飾器的call ()將調用每個方法裝飾器“second_init()”方法,並將類傳遞給那里。

有趣的是,method_decorator的call ()將在class_decorator之前調用。

如果您使裝飾器返回的對象成為描述符 ,那么您可以掛鈎屬性查找以返回鏈接方法和類(或實例)的其他對象。

對於方法樣式描述符,您只需要實現__get__方法。 在類上查找方法時,以下兩個是等效的:

m = MyClass.decorated_method
# It will actually get the object from any parent class too.  But this will do for a simple example
m = MyClass.__dict__['decorated_method'].__get__(MyClass)

例如,以下內容是等效的:

instance = MyClass()
m = instance.decorated_method
m = type(instance).__dict__['decorated_method'].__get__(instance, type(instance))

所以表達式instance.decorated_method(...)實際上調用了__get__方法返回的對象。 這是允許簡單函數對象轉換為添加隱式self參數的綁定方法對象的相同過程。

創建此可調用對象時,您應該擁有所需的所有信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM