Python 在运行时添加方法
Python Adding Methods at runtime
我正在尝试在运行时向 classes 动态添加方法,但发现了一些问题:
#Here we define a set of symbols within an exec statement and put them into the dictionary d
d = {}
exec "def get_%s(self): return self.%s" % (attr_name, attr) in d
#Now, we bind the get method stored in d['get_%s'] to our object (class)
func = d['get_%s' % (attr_name)].__get__(d['get_%s' % (attr_name)], class)
setattr(class_instance, func.__name__, func)
当我尝试调用生成的 get 方法时,我看到以下内容:
Traceback (most recent call last):
File "Textere_AdvancedExample.py", line 77, in <module>
count = fact.get_counter()
File "<string>", line 1, in get_counter
AttributeError: 'function' object has no attribute '_counter'
编辑
根据目前给出的一些特殊回复,我想我需要澄清一下我为什么要这样做。
我正在尝试构建如下例所示的注释:
@getters
@singleton
class A() {
def __init__(self):
self._a = "a"
self._b = "b"
}
根据 class 中存在的名称,注释将在运行时为私有 class 变量构建 getter,并将它们绑定到单例实例。
我采取的策略是让应用程序上下文 class 带有一组字典。然后,上下文被传递给注解,注解将实例 & class 添加到这些字典中。
启动时,Application Context 负责读取字典,然后构建 get 方法并将其绑定到相应的单例对象。
编辑2
所以这个开发是在与我的 Java 开发人员朋友讨论后开始的,特别是关于两个库:Spring & Lombok
我想看看这些特定功能是否可以在 Python 中实现。因此,应用程序上下文最初是通过尝试获得类似于 Spring 的自动装配注释的功能而产生的。我让这个工作没有问题。
然后,我得到了生成 getter 和 setter 的方法,并意识到我将在 Python 和 Java 实现中有一个根本的区别:Lombok 在编译时执行此操作并且 Python 未编译。这意味着我必须根据所注释的内容动态生成方法并将它们手动绑定到对象,所有这些都在运行时进行。因此,您会看到 Java 实现的这种扭曲。
对于那些感兴趣的人,可以找到完整的代码here
exec("%s.__dict__['get_%s'] = lambda self: self.%s" % (class_name, attr_name, attr_name))
您可以轻松地动态添加静态方法或 class 方法:
class A:
pass
@staticmethod
def foo0(x):
return x * 2
a = A()
A.foo = foo0
a.foo(3)
return 6
class A:
val = 3
@classmethod
def foo0(cls, x):
return x * cls.val
a = A()
A.foo = foo0
a.foo(2)
return 6
您还可以将特定方法添加到 class 的实例(几乎相同的方式)
class A:
pass
a = A()
a.foo = (lambda x: 2*x)
a.foo(3)
returns 6
您还可以通过使用 types
模块向 class 添加实例方法(事实上,这种通用方法也可用于创建静态和 class 方法,以及仅实例方法):
class A:
def __init__(self, val):
self.val = val
a = A(3)
A.foo = types.MethodType((lambda self, x: self.val * x), None, A)
a.foo(2)
returns 6
但这确实是 monkey patching,这是一种快速而肮脏的 hack,只有在您需要通过略微更改的 classes 并且不允许更改名称时才应使用。向 class 添加功能的简洁方法是 inheritance
只是为了让这个答案更好,以上内容对Python 2.
有效
对于Python3,只能使用第一种方式创建class和静态方法,因为types
模块丢失了很多类型
然后你创建一个实例方法就像:
class A:
def __init__(self, val):
self.val = val
a = A(3)
A.foo = (lambda self, x: self.val * x)
a.foo(2)
returns 6
。这里不需要特殊构造
我正在尝试在运行时向 classes 动态添加方法,但发现了一些问题:
#Here we define a set of symbols within an exec statement and put them into the dictionary d
d = {}
exec "def get_%s(self): return self.%s" % (attr_name, attr) in d
#Now, we bind the get method stored in d['get_%s'] to our object (class)
func = d['get_%s' % (attr_name)].__get__(d['get_%s' % (attr_name)], class)
setattr(class_instance, func.__name__, func)
当我尝试调用生成的 get 方法时,我看到以下内容:
Traceback (most recent call last):
File "Textere_AdvancedExample.py", line 77, in <module>
count = fact.get_counter()
File "<string>", line 1, in get_counter
AttributeError: 'function' object has no attribute '_counter'
编辑
根据目前给出的一些特殊回复,我想我需要澄清一下我为什么要这样做。
我正在尝试构建如下例所示的注释:
@getters
@singleton
class A() {
def __init__(self):
self._a = "a"
self._b = "b"
}
根据 class 中存在的名称,注释将在运行时为私有 class 变量构建 getter,并将它们绑定到单例实例。
我采取的策略是让应用程序上下文 class 带有一组字典。然后,上下文被传递给注解,注解将实例 & class 添加到这些字典中。
启动时,Application Context 负责读取字典,然后构建 get 方法并将其绑定到相应的单例对象。
编辑2
所以这个开发是在与我的 Java 开发人员朋友讨论后开始的,特别是关于两个库:Spring & Lombok
我想看看这些特定功能是否可以在 Python 中实现。因此,应用程序上下文最初是通过尝试获得类似于 Spring 的自动装配注释的功能而产生的。我让这个工作没有问题。
然后,我得到了生成 getter 和 setter 的方法,并意识到我将在 Python 和 Java 实现中有一个根本的区别:Lombok 在编译时执行此操作并且 Python 未编译。这意味着我必须根据所注释的内容动态生成方法并将它们手动绑定到对象,所有这些都在运行时进行。因此,您会看到 Java 实现的这种扭曲。
对于那些感兴趣的人,可以找到完整的代码here
exec("%s.__dict__['get_%s'] = lambda self: self.%s" % (class_name, attr_name, attr_name))
您可以轻松地动态添加静态方法或 class 方法:
class A:
pass
@staticmethod
def foo0(x):
return x * 2
a = A()
A.foo = foo0
a.foo(3)
return 6
class A:
val = 3
@classmethod
def foo0(cls, x):
return x * cls.val
a = A()
A.foo = foo0
a.foo(2)
return 6
您还可以将特定方法添加到 class 的实例(几乎相同的方式)
class A:
pass
a = A()
a.foo = (lambda x: 2*x)
a.foo(3)
returns 6
您还可以通过使用 types
模块向 class 添加实例方法(事实上,这种通用方法也可用于创建静态和 class 方法,以及仅实例方法):
class A:
def __init__(self, val):
self.val = val
a = A(3)
A.foo = types.MethodType((lambda self, x: self.val * x), None, A)
a.foo(2)
returns 6
但这确实是 monkey patching,这是一种快速而肮脏的 hack,只有在您需要通过略微更改的 classes 并且不允许更改名称时才应使用。向 class 添加功能的简洁方法是 inheritance
只是为了让这个答案更好,以上内容对Python 2.
有效对于Python3,只能使用第一种方式创建class和静态方法,因为types
模块丢失了很多类型
然后你创建一个实例方法就像:
class A:
def __init__(self, val):
self.val = val
a = A(3)
A.foo = (lambda self, x: self.val * x)
a.foo(2)
returns 6
。这里不需要特殊构造