简体   繁体   English

如何避免python中的循环引用-类成员创建另一个类的对象并将self作为参数传递?

[英]How to avoid circular reference in python - a class member creating an object of another class and passing self as parameter?

I need some help in terms of 'pythonic' way of handling a specific scenario.在处理特定场景的“pythonic”方式方面,我需要一些帮助。

I'm writing an Ssh class (wraps paramiko) that provides the capability to connect to and executes commands on a device under test (DUT) over ssh.我正在编写一个 Ssh 类(包装 paramiko),它提供了通过 ssh 连接到被测设备 (DUT) 并在其上执行命令的能力。

class Ssh:
    def connect(some_params):
        # establishes connection
    def execute_command(command):
        # executes command and returns response
    def disconnect(some_params):
        # closes connection

Next, I'd like to create a Dut class that represents my device under test.接下来,我想创建一个代表我的被测设备的 Dut 类。 It has other things, besides capability to execute commands on the device over ssh.除了通过 ssh 在设备上执行命令的能力之外,它还具有其他功能。 It exposes a wrapper for command execution that internally invokes the Ssh's execute_command.它公开了一个用于在内部调用 Ssh 的 execute_command 的命令执行的包装器。 The Ssh may change to something else in future - hence the wrapper. Ssh 将来可能会更改为其他内容 - 因此是包装器。

def Dut:
    def __init__(some params):
        self.ssh = Ssh(blah blah)

    def execute_command(command)
        return self.ssh.execute_command(command)

Next, the device supports a custom command line interface for device under test.接下来,该设备支持用于被测设备的自定义命令行界面。 So, a class that accepts a DUT object as an input and exposes a method to execute the customised command.因此,一个接受 DUT 对象作为输入并公开执行自定义命令的方法的类。

def CustomCli:
    def __init__(dut_object):
        self.dut = dut_object
    def _customize(command):
        # return customised command
    def execute_custom_command(command):
        return self.dut.execute_command(_customize(command))

Each of the classes can be used independently (CustomCli would need a Dut object though).每个类都可以独立使用(尽管 CustomCli 需要一个 Dut 对象)。

Now, to simplify things for user, I'd like to expose a wrapper for CustomCli in the Dut class.现在,为了简化用户的操作,我想在 Dut 类中为 CustomCli 公开一个包装器。 This'll allow the creator of the Dut class to exeute a simple or custom command.这将允许 Dut 类的创建者执行一个简单的或自定义的命令。 So, I modify the Dut class as below:所以,我修改 Dut 类如下:

def Dut:
    def __init__(some params):
        self.ssh = Ssh(blah blah)
        self.custom_cli = Custom_cli(self) ;# how to avoid this circular reference in a pythonic way?

    def execute_command(command)
        return self.ssh.execute_command(command)

    def execute_custom_command(command)
        return self.custom_cli.execute_custom_command(command)

This will work, I suppose.我想这会奏效。 But, in the process I've created a circular reference - Dut is pointing to CustomCli and CustomCli has a reference to it's creator Dut instance.但是,在这个过程中,我创建了一个循环引用——Dut 指向 CustomCli,而 CustomCli 引用了它的创建者 Dut 实例。 This doesn't seem to be the correct design.这似乎不是正确的设计。 What's the best/pythonic way to deal with this?处理这个问题的最佳/pythonic 方法是什么?

Any help would be appreciated!任何帮助将不胜感激!

Regards问候

Sharad沙拉德

In general, circular references aren't a bad thing.一般来说,循环引用并不是一件坏事。 Many programs will have them, and people just don't notice because there's another instance in-between like A->B->C->A .许多程序都会有它们,人们只是没有注意到,因为中间还有另一个实例,例如A->B->C->A Python's garbage collector will properly take care of such constructs. Python 的垃圾收集器将妥善处理此类构造。

You can make circular references a bit easier on your conscience by using weak references.您可以通过使用弱引用使循环引用更容易一些。 See the weakref module.请参阅weakref模块。 This won't work in your case, however.但是,这不适用于您的情况。

If you want to get rid of the circular reference, there are two way:如果你想摆脱循环引用,有两种方法:

  1. Have CustomCLI inherit from Dut , so you end up with just one instance.有无CustomCLI继承Dut ,所以你只用一个实例结束。 You might want to read up on Mixins.你可能想阅读 Mixins。

     class CLIMerger(Dut): def execute_custom_command(command): return self.execute_command(_customize(command)) # use self^ instead of self.dut class CLIMixin(object): # inherit from object, won't work on its own def execute_custom_command(command): return self.execute_command(_customize(command)) # use self^ instead of self.dut class CLIDut(Dut, CLIMixin): # now the mixin "works", but still could enhance other Duts the same way pass

    The Mixin is advantageous if you need several cases of merging a CLI and Dut.如果您需要合并 CLI 和 Dut 的几种情况,则 Mixin 是有利的。

  2. Have an explicit interface class that combines CustomCli and Dut .有结合了明确的接口类CustomCliDut

     class DutCLI(object): def __init__(self, *bla, **blah): self.dut = Dut(*bla, **blah) self.cli = CustomCLI(self.dut)

    This requires you to write boilerplate or magic to forward every call from DutCLI to either dut or cli .这需要您编写样板文件或魔术来将来自DutCLI每个调用DutCLIdutcli

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM