我想通过元类做到以下几点:
1.获取基于它产生的类的,具有特定命名规则的函数列表
2.列表里面的函数可以直接被调用,而无需做多余额外的操作
关键是第二点该如何操作?
例如列表 lst=[func1, func2]
,我想实现的是可以直接通过func1()
、func2()
这种方式来运行函数
我目前能做到的解决方案是
class Metaclass(type):
func_list = []
def __new__(cls, name, base, attrs):
obj = type.__new__(cls, name, base, attrs)()
for k,v in attrs.items():
if k.startswith('at'):
func = obj.__getattribute__(k)
Metaclass.func_list.append(func)
return type.__new__(cls, name, base, attrs)
class A(object, metaclass=Metaclass):
def at_func1(self):
print('A_func1')
def at_func2(self):
print('A_func2')
请问这是最优的吗?或者一般的解决方法是什么?
有没有办法在元类里面不创建 obj 的情况下,实现我上面的需求?
即obj = type.__new__(cls, name, base, attrs)()
没有这行代码
因为 obj 并不会随着元类创建类的完毕而销毁,会有一个元类创建的实例对象( obj )常驻内存,而这个实例有太多额外的东西是不需要的,我仅仅需要的是里面的两个特定函数at_func1
和at_func2
如果我把下面的at_func1(self)
里面的 self 删掉,确实可以实现,不创建实例的情况下完成上面的需求
但是这样导致的另一个结果就是,我如果自己在其他地方新建一个 a=A()的实例,那么执行a.at_func1()
就会报错,有没有办法能权衡这两点?
满足需求的情况下,
1.在元类里面无需创建 obj
2.在元类外面A().at_func1()
能正常运行
1
NullPoint 2019-06-29 18:32:40 +08:00 via Android
把两个方法变成静态方法就可以了吧,都不需要元类
|
2
BingoXuan 2019-06-29 18:56:34 +08:00 via Android
你是想把一个多个符合特定格式的实例方法加到一个类里面吗?
那直接构建一个类,其中一个类方法是通过 getattr 获取实例的方法,并加入类属性里面。如果实例方法的 self 要指定,那么用 function tool 的 partial 指定一个对象作为 self 传进去就好了。 |
3
Dilras 2019-06-29 20:15:34 +08:00
不需要创建 obj,atts 字典里面本身就存着函数对象,所以直接 append 就好了
```python class Metaclass(type): func_list = [] def __new__(mcs, name, base, attrs): for k,v in attrs.items(): if k.startswith('at'): mcs.func_list.append(v) return type.__new__(mcs, name, base, attrs) ``` |
4
caneman OP @NullPoint 方法和类后续都会扩展,直接用静态方法的话,没有办法维持一个满足给定条件的全部函数集合。
@BingoXuan 我想实现的大概是这样一种场景,我创建一个元类,和若干子类,子类可能随时会扩展,但是我需要的仅仅是子类中满足特定格式命名的方法(实例方法、类方法、静态方法等都可以),我想在元类里面创建一个列表,里面是所有满足条件的方法的集合,如:func_list = [fun1, fun2, fun3],我想使这个列表中的元素(即每一个函数)可以直接执行,如:fun1()、func2(),而不需要其余多余的操作。 @Dilras attrs 中 v 确实存的是函数的引用,但是是无法通过直接在其后面加括号运行的( func1())这种方法运行的,会提示缺少(self)参数,如果改成将 func1 改成类方法就会提示缺少(cls),如果什么都不填( def func1():return 'xx'),那么我在其他地方实例化这个类,A().func1()就无法运行了...,( A.func1()也不行) 我的问题实质可能是,能否把一个类通过某些手段转换成一个变量+函数的集合,不具有其他多余的东西(类似于闭包的感觉),同时在其他情况下能够保留类本身的特性。 |
5
lrxiao 2019-06-29 21:24:25 +08:00
没搞懂 那不同的 self 怎么区分? 除非你这个类是单例
|
6
BingoXuan 2019-06-30 18:13:52 +08:00
@caneman
“”“我的问题实质可能是,能否把一个类通过某些手段转换成一个变量+函数的集合,不具有其他多余的东西(类似于闭包的感觉),同时在其他情况下能够保留类本身的特性。”“” 这个设计有点不明所以,连你自己都不确定自己要什么,能实现什么功能,方便解决什么问题。总感觉你是实现类似 go 的 duck typing 风格的类。但我觉得如果一个类解耦成函数和变量的集合。应该通过类的多继承实现 mixin。通过多继承数据类和方法类,最终自由的组合任意数据类型和函数,实现高度解耦。甚至代理模式也可以。通过 override 代理类的__getattribute__方法,代理特定数据对象和方法对象的所有属性和方法。你甚至可以在__getattribute__这个方法里面通过访问 globals 获取当前所有定义的类的方法或者函数,再把数据扔进去执行。但这种 trick 我觉得都是苦劳。 普通的继承也可以把所有子类的对象捆绑到最终的父类对象上。在子类实例化时候,把子类的所有符合条件方法绑定到父类属性里面(下面代码我默认全部公开的实例方法绑定),你可能需要修改一下判断条件。对静态函数,方法,类函数等,可能需要用 functiontool 这个库进行修改参数,比如去掉 self,指定默认 self 等等。 class A: subclass_list = [] def __init__(self): for attr in dir(self): if not attr.startswith('__') and isinstance(getattr(self,attr),MethodType): self.__class__.subclass_list.append(getattr(self,attr)) |
7
frostming 2019-07-01 11:26:35 +08:00
你为什么可以用一个 dummy 的实例去调用方法呢?那我要指定实例怎么办?
如果调用方法跟 self 是什么没关系的话,你用 staticmethod 不就不用这个 obj 了吗? 你的想法和你的解决方法互相矛盾,叫人如何回答 |
8
caneman OP @BingoXuan 谢谢。
我重新整理了下我的需求, 1. 有很多功能模块,每个功能模块里面有若干方法,在主线程里面,我只需要用到这些模块的某些特定方法,不需要实例化这些功能模块,仅仅调用方法。(这种情况下,每个模块类似于变量+方法的集合)。 2.在某些子线程里面,可能会实例化某一个功能模块(这种情况下,模块就是一般的类)。 3.另一个需要满足的是,我需要有一个功能模块中心,它能够自动感知功能模块的增删,以及去所有功能模块里面收集并维持一个满足条件的方法列表。 这样做的目的在于,我的主线程中的业务逻辑只需要关注功能模块中心即可,增删功能模块,不需要对其它地方做额外的变动。 因为绝大多数的情况下,都是 1 在发挥作用,极少数情况下才会用到 2,所以我不希望在 1 的时候需要实例化每个功能模块,因为实例化带来的附加属性我是完全用不到,虽然也占不到几个内存。当时之所以采用元类的方式来解决,也是出于这一点,不需要实例化子类的情况下,便能完成子类中属性方法的获取。 @frostming 采用静态方法的化,我如何才能获得这个静态方法的引用呢?即 func1 这个变量如何才能指向 A.func1(),以便我 func1()便能 A.func1(),__getattr__不是实例方法吗,元类里面 attrs 里面存的函数引用,对于静态方法也是不能直接执行。 for k,v in attrs.items(): v()这样是不行的 现在的情况,我基本放弃 1 的需求了,实例就实例把,也占不了太多东西,这样的化解决方案就很多了, @BingoXuan @frostming 的方法都可以实现我的需求了。 |