关于oop:在python中组合来自2个类的函数

combining functions from 2 classes in python

我有以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import time

class output_letter():

    def output_a(self):
        print('a')
    def output_b(self):
        print('b')
    def output_c(self):
        print('c')
    .............
    def output_z(self):
        print('z')
class wait_time():

    def sleep_2(self):
        time.sleep(2)

out = output_letter()
out.output_a()

我想将类wait_time.sleep_2的功能附加到类输出字母的开头。例如,如果我创建一个假设类"组合",我可以这样做

1
2
c=combined()
c.output_a # would wait 2 seconds and then print 'a'

问题是我不想重写"output"字母的所有函数,我只想在它的所有函数中添加相同的功能。

我不清楚如何做到这一点,也不清楚继承或组合是否可能做到这一点。


我看到了你可能希望如何基于干练和坚实的原则来解决两个独立的任务:

  • 将来在许多其他地方应用wait_time应该很容易。
  • 尽可能保持output_letter的清洁和不可接触是很酷的。
  • 我的想法是:

    1。创建一个模块,允许您为所有方法应用一个修饰器:

    1
    2
    3
    4
    5
    6
    7
    def for_all_methods(decorator):
        def decorate(cls):
            for attr in cls.__dict__:
                if callable(getattr(cls, attr)):
                    setattr(cls, attr, decorator(getattr(cls, attr)))
            return cls
        return decorate

    2。隔离模块中的wait_time

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from time import sleep

    class wait_time():
        @staticmethod
        def sleep_decorator(function):
            def wrapper(*args, **kwargs):
                #sleep(2)
                print("sleeping")
                return function(*args, **kwargs)
            return wrapper

    三。这就是你如何使用它

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @for_all_methods(wait_time.sleep_decorator)
    class output_letter():

        def output_a(self):
            print('a')

        def output_b(self):
            print('b')

        def output_c(self):
            print('c')

        def output_z(self):
            print('z')

    因此,好处是,我们实际上并没有涉及构造函数或更改继承。我们所做的一切,只是在类上面添加了一个修饰器,在必要的时候很容易启用或禁用。

    如果您想更进一步,避免直接处理原始类,您只需创建从原始类继承的子Combined,并在其定义之上添加装饰器签名。

    你可以试试这个演示


    您在示例中显示的所有类都不是非常好的OOP设计。当方法不引用任何状态时,不需要类。如果只需要一个名称空间,通常模块更好。

    但如果你的问题真的是关于如何组合多个函数的效果,这并不重要。有很多方法可以做到这一点。函数是Python中的第一类对象,因此您可以将它们放在列表或字典中,或者根据需要将它们作为参数传递给其他函数。您还可以创建"函数工厂",即返回新函数的函数。

    以下是您如何使用它来构建所需的延迟写信功能。我将函数结果存储在几个字典中,但是如果需要,您可以对它们做一些不同的事情。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import itertools
    import time

    def letter_writer_factory(letter):
       """Return a function that prints the provided letter when it is called"""
        def func():
            print(letter)
        return func

    def delay_factory(seconds):
       """Return a function that when called, waits for the specified time"""
        def delay():
            time.sleep(seconds)
        return delay

    def function_sequencer_factory(*functions):
       """Return a function that calls each function argument in turn"""
        def caller():
            for func in functions:
                func()
        return caller

    letters = 'abc'
    delay_times = [2, 5, 10]
    output_funcs = {c: letter_writer_factory(c) for c in letters}
    delay_funcs = {t: delay_factory(t) for t in delay_times}
    delayed_output_funcs = {(c, t): function_sequencer_factory(df, of)
                            for (c, of), (t, df) in itertools.product(output_funcs.items(),
                                                                      delay_funcs.items())}

    #print c after waiting for 10 seconds:
    delayed_output_funcs['c', 10]()

    当然,这是一个非常愚蠢的例子,但是在某些上下文中,这些类型的函数式编程技术可以用来做一些实际有用的事情。


    您可以在output_letter中创建wait_time的类实例作为属性,也可以在方法本身中调用time.sleep

    选项1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import time
    class wait_time():
       def sleep_2(self):
         time.sleep(2)

    class output_letter():
      def __init__(self):
          self.wait = wait_time()
      def output_a(self):
         self.wait.sleep_2()
         print('a')
      def output_b(self):
         self.wait.sleep_2()
         print('b')
      def output_c(self):
         self.wait.sleep_2()
         print('c')

    选项2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class output_letter():
       def output_a(self):
          time.sleep(2)
          print('a')
        def output_b(self):
          time.sleep(2)
          print('b')
        def output_c(self):
          time.sleep(2)
          print('c')

    编辑:关于您最近的评论和编辑,您可能只需要创建两个实例并分别调用:

    1
    2
    3
    4
    a = outout_letter()
    t = wait_time()
    t.sleep_2()
    a.output_a()

    另外,似乎您正在尝试输出输出的每个字母,给定一个方法调用,目标字母在末尾。为了缩短代码并实现wait_time,可以使用__getattr__

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Output_Letter:
        def __init__(self):
            self.t = wait_time()
        def __getattr__(self, name):
             def wrapper():
                 self.t.sleep_2()
                 print name.split('_')[-1]
             return wrapper

    a = Output_Letter()
    a.output_c()

    输出:

    1
    c


    可以将多个类划分为子类。在Python 3中:

    鉴于

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import time


    class Letter():
       "Print a letter."""
        def output_a(self):
            print('a')

        def output_b(self):
            print('b')

        def output_c(self):
            print('c')


    class WaitTime():
       """Set a delay."""
        def sleep_2(self):
            time.sleep(2)

    代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Combined(Letter, WaitTime):
       """Combine methods."""
        def output_a(self):
            super().sleep_2()
            super().output_a()


    combined = Combined()
    combined.output_a()
    # 'a'                                              # delayed output

    这允许您保留原始类。你只需在新的Combined类中调用它们。

    细节

    Combined类将其他类混合在一起。super()函数根据类方法解析顺序调用这些高级类来访问它们的方法:

    1
    2
    Combined.__mro__
    # (__main__.Combined, __main__.Letter, __main__.WaitTime, object)

    为了在Python2中工作,需要进行一些调整:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Letter(object):
        ...

    class WaitTime(object):
        ...

    class Combined(Letter, WaitTime):

        def output_a(self):
            super(Combined, self).sleep_2()
            super(Combined, self).output_a()

    小提示:为了可读性,请为类使用camelcase名称。类名通常是名词;函数通常是动词。


    下面的代码实现了您想要的。您可以在组合类中设置类变量来表示输出字母和等待时间。然后在组合类内部,您可以访问其他类的所有属性和函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import time
    class output_letter():
        def output_a(self):
            print('a')
        def output_b(self):
            print('b')
        def output_c(self):
            print('c')
    class wait_time():
        def sleep_2(self):
            time.sleep(2)
    class combined():
        ol = output_letter()
        wt = wait_time()
        def output_a(self):
            self.wt.sleep_2()
            self.ol.output_a()

    def main():
        c=combined()
        c.output_a()

    if __name__ == '__main__':
        main()