如何用python创建动态方法?

时间:2016-07-25 18:30:59

标签: python django

对于我的项目,我需要动态创建自定义(Class)方法。

我发现在Python中并不容易:

class UserFilter(django_filters.FilterSet):
    '''
    This filter is used in the API
    '''
    # legacy below, this has to be added dynamically
    #is_field_type1 = MethodFilter(action='filter_field_type1') 

    #def filter_field_type1(self, queryset, value):
    #    return queryset.filter(related_field__field_type1=value)

    class Meta:
        model = get_user_model()
        fields = []

但它给了我错误(和头痛......)。这甚至可能吗?

我尝试在#legacy dynamic

之间创建代码

我发现这样做的一个选择是动态创建类

def create_filter_dict():
    new_dict = {}
    for field in list_of_fields:

        def func(queryset, value):
            _filter = {'stableuser__'+field:value}
            return queryset.filter(**_filter)

        new_dict.update({'filter_'+field: func})

        new_dict.update({'is_'+field: MethodFilter(action='filter_'+field)})

    return new_dict


meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)

filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('UserFilter', (django_filters.FilterSet,), filter_dict)

然而,这是给了我

TypeError at /api/v2/users/
func() takes 2 positional arguments but 3 were given

有谁知道如何解决这个难题?

3 个答案:

答案 0 :(得分:1)

  

例外值:' UserFilter'对象没有属性' is_bound'

您收到此错误是因为您生成的类方法未绑定到任何类。要将它们绑定到类,您需要使用setattr()

在控制台上试试这个:

class MyClass(object):
    pass

@classmethod 
def unbound(cls):
    print "Now I'm bound to ", cls


print unbound
setattr(MyClass, "bound", unbound) 
print MyClass.bound 
print MyClass.bound()
  

回溯:       UserFilter = type(' Foo',(django_filters.FilterSet,),create_filter_dict()。update({' Meta':type(' Meta',(), {'模型&#39 ;:   get_user_model(),' fields':[]})}))TypeError:type()参数3必须   是dict,而不是没有

现在,这是失败的,因为dict.update()没有返回相同的实例,返回None。这很容易修复

class_dict = create_filter_dict()
class_dict.update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}
UserFilter = type('Foo', (django_filters.FilterSet, ), class_dict))

然而,看看代码看起来有多乱。我建议你尝试做 使用您编写的代码更清晰,即使它需要写一些额外的行。从长远来看,代码将更易于为您和您的团队维护。

meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)

filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('Foo', (django_filters.FilterSet,), filter_dict)

此代码可能不完美,但它比您发布的原始代码行更具可读性:

UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}))

并消除了一个已经有点难以理解的概念的复杂性。

您可能想了解元类。也许你可以覆盖一个类的 new 方法。我可以向您推荐12个帖子。

另一种选择是,你可能没有正确地添加过滤器或django没有预料到的方式?这可以解释为什么你没有错误,但没有任何函数被调用。

答案 1 :(得分:0)

您可以使用classmethod。以下是如何使用它的示例:

class UserFilter:
    @classmethod
    def filter_field(cls, queryset, value, field = None):
        # do somthing
        return "{0} ==> {1} {2}".format(field, queryset, value)
    @classmethod
    def init(cls,list_of_fields ):
        for field in list_of_fields:
            ff = lambda cls, queryset, value, field=field: cls.filter_field(queryset, value, field )
            setattr(cls, 'filter_'+field, classmethod( ff ))

UserFilter.init( ['a','b'] )
print(UserFilter.filter_a(1,2)) # a ==> 1 2
print(UserFilter.filter_b(3,4)) # b ==> 3 4

答案 2 :(得分:0)

你要求:

  

自定义(类)方法。

因此我们采用一个现有的类并派生一个子类,您可以在其中添加新方法或覆盖原始现有类的方法(查看所需方法的原始类的代码),如下所示:

from universe import World
class NewEarth(World.Earth):
   def newDirectionUpsideDown(self,direction):
       self.rotationDirection = direction

World.Earth的所有其他方法和功能仅适用于NewEarth,您现在可以改变方向,让世界转向新的方向。

要覆盖类的现有方法就像这样容易。

class NewEarth(World.Earth):
   def leIitRain(self,amount): # let's assume leIitRain() is a standard-function of our world
       return self.asteroidStorm(amount) #let's assume this is possible Method of World.Earth

所以,如果有人喜欢在地球上淋浴,那么他/她就可以在玩具大理石上以新的发展方式腾出空间。

所以学习python的方式很有趣 - 而且不要从复杂的事情开始。

如果我弄错了你 - 你可以更详细地解释你的问题 - 所以比我更聪明的人可以分享他们的智慧。