使用实例属性中的关键字的方法

时间:2017-01-29 15:05:07

标签: python class methods attributes keyword-argument

完美但不可能的情景是:

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'的行为。我的准备解决方案太耗时。在对代码进行分析之后,我认为它仅在准备时间内花费了12秒。这样做的聪明且耗时少的方法是什么?我完全迷失了。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我发现了六种做我想做的事情。在分析代码之后,结果是:

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函数,只是为了保证它们具有相同的基本结构,因此时间差异来自循环。