当前位置: 首页 > 面试题库 >

在Python中执行自动属性分配的最佳方法是什么,这是个好主意吗?

微生曾琪
2023-03-14
问题内容

每次定义一个类时,无需像这样编写代码:

class Foo(object): 
     def __init__(self, a, b, c, d, e, f, g):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f
        self.g = g

我可以使用此配方进行自动属性分配。

class Foo(object):
     @autoassign
     def __init__(self, a, b, c, d, e, f, g):
        pass

两个问题

  1. 此快捷方式是否有缺点或陷阱?
  2. 有没有更好的方法来实现类似的便利?

问题答案:

关于自动分配代码的某些问题会困扰我(主要是样式问题,但还有一个更严重的问题):

  1. autoassign 没有分配’args’属性:

    class Foo(object):
    @autoassign
    def __init__(self,a,b,c=False,*args):
        pass
    

    a=Foo(‘IBM’,’/tmp’,True, 100, 101)
    print(a.args)

  2. autoassign就像一个装饰者。但是autoassign(*argnames)调用一个返回装饰器的函数。要实现这种魔力,autoassign 需要测试其第一个参数的类型。如果可以选择的话,我更喜欢函数而不是测试其参数的类型。

  3. 似乎有大量代码专门用于设置 sieve,lambda中的lambda,ifilter和许多条件。

    if kwargs:
    exclude, f = set(kwargs['exclude']), None
    sieve = lambda l:itertools.ifilter(lambda nv: nv[0] not in exclude, l)
    

    elif len(names) == 1 and inspect.isfunction(names[0]):
    f = names[0]
    sieve = lambda l:l
    else:
    names, f = set(names), None
    sieve = lambda l: itertools.ifilter(lambda nv: nv[0] in names, l)

我认为可能有一种更简单的方法。(见下文)。

  1. for _ in itertools.starmap(assigned.setdefault, defaults): pass。我不认为 mapstarmap打算调用函数,函数的唯一目的是它们的副作用。可以用平凡的方式写得更清楚:
    for key,value in defaults.iteritems():
    assigned.setdefault(key,value)
    

这是一个替代性的更简单的实现,它具有与自动分配相同的功能(例如可以进行包含和排除),并且可以解决上述问题:

import inspect
import functools

def autoargs(*include, **kwargs):
    def _autoargs(func):
        attrs, varargs, varkw, defaults = inspect.getargspec(func)

        def sieve(attr):
            if kwargs and attr in kwargs['exclude']:
                return False
            if not include or attr in include:
                return True
            else:
                return False

        @functools.wraps(func)
        def wrapper(self, *args, **kwargs):
            # handle default values
            if defaults:
                for attr, val in zip(reversed(attrs), reversed(defaults)):
                    if sieve(attr):
                        setattr(self, attr, val)
            # handle positional arguments
            positional_attrs = attrs[1:]
            for attr, val in zip(positional_attrs, args):
                if sieve(attr):
                    setattr(self, attr, val)
            # handle varargs
            if varargs:
                remaining_args = args[len(positional_attrs):]
                if sieve(varargs):
                    setattr(self, varargs, remaining_args)
            # handle varkw
            if kwargs:
                for attr, val in kwargs.items():
                    if sieve(attr):
                        setattr(self, attr, val)
            return func(self, *args, **kwargs)
        return wrapper
    return _autoargs

这是我用来检查其行为的单元测试:

import sys
import unittest
import utils_method as um

class Test(unittest.TestCase):
    def test_autoargs(self):
        class A(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False):
                pass
        a=A('rhubarb','pie',debug=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)

        class B(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False,*args):
                pass
        a=B('rhubarb','pie',True, 100, 101)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)
        self.assertTrue(a.args==(100,101))

        class C(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False,*args,**kw):
                pass
        a=C('rhubarb','pie',True, 100, 101,verbose=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)
        self.assertTrue(a.verbose==True)        
        self.assertTrue(a.args==(100,101))

    def test_autoargs_names(self):
        class C(object):
            @um.autoargs('bar','baz','verbose')
            def __init__(self,foo,bar,baz,verbose=False):
                pass
        a=C('rhubarb','pie',1)
        self.assertTrue(a.bar=='pie')
        self.assertTrue(a.baz==1)
        self.assertTrue(a.verbose==False)
        self.assertRaises(AttributeError,getattr,a,'foo')

    def test_autoargs_exclude(self):
        class C(object):
            @um.autoargs(exclude=('bar','baz','verbose'))
            def __init__(self,foo,bar,baz,verbose=False):
                pass
        a=C('rhubarb','pie',1)
        self.assertTrue(a.foo=='rhubarb')
        self.assertRaises(AttributeError,getattr,a,'bar')

    def test_defaults_none(self):
        class A(object):
            @um.autoargs()
            def __init__(self,foo,path,debug):
                pass
        a=A('rhubarb','pie',debug=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)


if __name__ == '__main__':
    unittest.main(argv = sys.argv + ['--verbose'])

PS。使用autoassignautoargs与IPython代码完成兼容。



 类似资料:
  • 问题内容: 在Python中,我有以下示例类: 如您所见,我有一个简单的“私有”属性“ _attr”和一个用于访问它的属性。有很多代码可以声明一个简单的私有属性,我认为这样声明所有属性并不符合“ KISS”哲学。 因此,如果我不需要特定的getter / setter / deleter,为什么不将我的所有属性都声明为公共属性呢? 我的回答是:因为封装原理(OOP)另有说明! 什么是最好的方法 ?

  • 问题内容: 我需要比较两个对象(同一类的实例)中的许多字段,并做一些记录和更新,以防出现差异。元代码可能看起来像这样: 具有所有比较的代码非常简洁,我想以某种方式使其更紧凑。如果我有一个方法可以将setter和getter的调用作为参数并在所有字段中调用,那将是很好的,但是不幸的是,这对于Java是不可能的。 我提出了三个选择,每个选择都有其自身的缺点。 1.使用反射API来找出getter和se

  • 问题内容: 是否有适用于javascript的良好分析器?我知道firebug对分析代码提供了一些支持。但是我想确定更大范围的统计数据。想象一下,您正在构建大量的javascript代码,并且您想确定代码中实际上是什么瓶颈。首先,我想查看每个javascript函数和执行时间的配置文件统计信息。接下来将包括DOM函数。这与放慢速度的操作(如对渲染树的操作)相结合将是完美的。我认为,如果在我的代码,

  • 我有一个超时执行任务的方法。我使用ExecutorServer.submit()获取一个Future对象,然后调用future.get()并超时。这很好,但是我的问题是处理我的任务可能抛出的检查异常的最好方法。下面的代码工作正常,并且保留了被检查的异常,但是如果方法签名中被检查的异常的列表改变了,它看起来非常笨拙并且容易出错。 关于如何解决这个问题的任何建议?我需要以Java 5为目标,但我也很好

  • 问题内容: 我想永远每60秒重复执行一次Python中的函数(就像中的一样)。该代码将作为守护程序运行,实际上就像使用每分钟调用脚本一样,但是不需要用户设置。 在有关使用Python实现的的问题中,该解决方案似乎实际上只是将停留了x秒。我不需要这种高级功能,所以也许这样的事情会起作用 该代码是否存在任何可预见的问题? 问题答案: 使用模块,该模块实现了通用事件调度程序。