【问题标题】:Methods with keywords from the instances's attributes带有来自实例属性的关键字的方法
【发布时间】:2017-06-14 19:23:04
【问题描述】:

完美但不可能的场景是:

class example(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def foo(self, x = self.x, y = self.y):
        return x + y

它不起作用,因为 self 没有定义。我做了很多研究,研究了装饰器、描述符、元类,几乎所有东西。解决方案可能是最明显和众所周知的,但我找不到。我可以管理两种解决方法,如下所示:

def prep(argslist, argsprovided, attributes):
        argsout = []
        for name in argslist:
            if name in argsprovided:
                argsout.append(argsprovided[name])
            else:
                argsout.append(getattr(attributes,name))

        return argsout

class example(object):

    # I can create a default instance or a custom one
    def __init__(self,x = 1,y = 1,z = 1,w = 1):

        self.x = x
        self.y = y
        self.z = z
        self.w = w

    # I can wrap a function to use the self argument       
    def wrapper(self):
        def foo(x = self.x, y = self.y, z = self.z, w = self.w):
            return x + y + z + w
        return foo

    # I can wrap 'joo' alongside with foo, and make 'wrapper' return a list    
    def joo(self, **kwargs):
        [x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
        return x + y + z + 2*w

    # I can use my custom 'prep' function to to the job
    def foo(self, **kwargs):
        [x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
        return x + y + z + w



# Creates a default instance and a custom one        
c = example()
d = example(2,2,2,2)

# I can use 'foo' with the instance's default values with both wrapping and 'prepping'
print(c.wrapper()())
print(d.wrapper()())
print(c.foo())
print(d.foo())

# I can use 'foo' with a mix of default values and provided values with both wrapping and 'prepping'
print(c.wrapper()(1,2,3))
print(d.wrapper()(1,2,3))
print(c.foo(y = 3,z = 4,w = 5))
print(d.foo(y = 3,z = 4,w = 5))

代码打印出来:

4
8
4
8
7
8
13
14

我有一个很大的类,有很多功能,每个人都需要'foo'的行为。我的准备解决方案太耗时了。分析代码后,我认为它只在 prep 中花费了 12 秒。有什么聪明且省时的方法来做到这一点?我完全迷路了。

【问题讨论】:

    标签: python class methods attributes keyword-argument


    【解决方案1】:

    我不确定它是否会有所帮助,但如何使用 None 作为默认值并使用子句来确定该值。例如:

    def foo(self, x=None, y=None):
        real_x = x if x != None else self.x
        real_y = y if y != None else self.y
        return real_x + real_y
    

    【讨论】:

    • 确实更快!这是一个不错的选择,但我的一些函数需要超过 10 个参数,所以这不是那么实用。包装器方法稍微慢一点。最好的方法是定义 k = c.wrapper() 然后使用 k()。
    【解决方案2】:

    我找到了六种方法来做我想做的事。分析代码后,结果是:

    afoo     foo       noo1     noo2     wrap1     wrap2
    6.730    28.507    3.98     4.097    10.256    3.468
    6.407    28.659    4.096    3.924    9.783     3.529
    6.277    28.450    3.946    3.889    10.265    3.685
    6.531    30.287    3.964    4.149    10.077    3.674
    

    正如您将看到的,noo1noo2wap2 在代码上非常相似。常规方法afoo 效率不高。我的自定义方法 foo 很糟糕,而 wrap1 只是为了完整性而进行了测试。

    afoo.py
    缺点是每个函数参数都需要额外的一行。

    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
        def afoo(self, x = None, y = None, z = None, w = None):
            x = x if x != None else self.x
            y = y if y != None else self.y
            z = z if z != None else self.z
            w = w if w != None else self.w
            return x + y + z + w
    
    
    c = example(2,2,2,2)
    for i in range(0, 10000000):
        c.afoo(1,2,3,4)
    

    foo.py
    这是一种较慢的方法。

    def prep(argslist, argsprovided, attributes):
            argsout = []
            for name in argslist:
                if name in argsprovided:
                    argsout.append(argsprovided[name])
                else:
                    argsout.append(getattr(attributes,name))
    
            return argsout
    
    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
        def foo(self, **kwargs):
            [x,y,z,w] = prep(['x','y','z','w'],kwargs,self)
            return x + y + z + w
    
    
    c = example(2,2,2,2)
    for i in range(0, 10000000):
        c.foo(x = 1,y = 2,z = 3,w = 4)
    

    wrapper1.py
    效率远低于wrapper2.py

    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
        def wrapper(self):
            def foo(x = self.x, y = self.y, z = self.z, w = self.w):
                return x + y + z + w
            return foo
    
    
    c = example(2,2,2,2)
    for i in range(0, 10000000):
        c.wrapper()(1,2,3,4)
    

    wrapper2.py

    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
        def wrapper(self):
            def foo(x = self.x, y = self.y, z = self.z, w = self.w):
                return x + y + z + w
            return foo
    
    
    c = example(2,2,2,2)
    k = c.wrapper()
    for i in range(0, 10000000):
        k(1,2,3,4)
    

    noo1.py

    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,U,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
            def noo(x = self.x, y = self.y, z = self.z, w = self.w):
                return x + y + z + w
    
            self.noo = noo
    
    c = example(2,2,2,2)
    for i in range(0, 10000000):
        c.noo(1,2,3,4)
    

    noo2.py

    class example(object):
    
        # I can create a default class or a custom one
        def __init__(self,x = 1,y = 1,z = 1,w = 1):
    
            self.x = x
            self.y = y
            self.z = z
            self.w = w
    
        def __call__(self):
            def noo(x = self.x, y = self.y, z = self.z, w = self.w):
                return x + y + z + w
    
            self.noo = noo
    
    
    c = example(2,2,2,2)
    c()
    for i in range(0, 10000000):
        c.noo(1,2,3,4)
    

    在测试这些代码时,我在所有代码中都包含了prep 函数,只是为了确保它们具有相同的基本结构,因此时间差将来自循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多