如果B类是A的子代,下面的代码会导致循环依赖吗? (为简单起见,我在A,B和A(),B()之间没有区别)
def random_function(B):
# get parent
par = B.A
do_stuff(par, B)
class A:
def method(self):
# get B
b = A.B
random_function(b)
# random_function will reference A now, but not via self, is this a problem?
我知道,这很容易解决
def random_function(A,B):
do_stuff(A, B)
class A:
def method(self):
# get B
b = A.B
random_function(self, b)
...但我想知道我是否仍然可以只用一个参数保留签名。
如果这太抽象了,这就是我要问的原因:在Blender中,有一个套接字类和一个节点类,其中套接字是节点的子节点。我有一个节点的子类和一个如下函数:
def func(socket):
# get parent
node = socket.node
do_stuff(node, socket)
class sub_class(Node):
def method(self):
func(self.Socket)
有没有办法让函数签名只有一个参数,而不是在这里遇到循环依赖?
编辑:提供一些实际代码和上下文的编辑,遵循评论中的建议
我将从类的描述开始,我认为这些类正在引起循环引用。
类ShaderNodeCustomGroup
代表一个节点 - 来自可视化编程的东西。它有套接字,它正在监听这些套接字上发生的事情。用户将输入连接到输入插座,可以从输出插座获得输出。基本上是非编程用户的功能的可视化表示。虚幻也有这个,但我的是来自Blender。
上面已经提到过类Socket
- 这是可以输入的内容以及输出的内容。
我不知道,它们究竟是如何交互的 - 这是在源代码中定义的,我只是使用API但是如果我执行以下操作,我会以某种方式崩溃整个应用程序:
导致崩溃的功能:
def get_socket_neighbor(socket, offset):
"""
get the neighbor of this socket, whose position is specified by the offset
RETURNS: a socket or OUT_OF_RANGE
NOTE: offset is not for the Blender socket order, it's acual movement by 'offset' socket up or down in world coordinates
"""
sock_ind = get_socket_index(socket, socket.node)
desired_position = sock_ind - offset # <--- the actual position in 'blender coordinates'
if desired_position > (len(socket.node.inputs)-1) or desired_position < 0:
return OUT_OF_RANGE
else:
return socket.node.inputs[desired_position]
对于节点中的套接字,这一个查找其邻居:例如,一个位置向上的套接字,或一个向下的位置(参见插图中的节点和套接字,套接字是小圆圈)。它做什么,它需要一个套接字,获取它所属的节点,推断出套接字的位置(sock_ind = get_socket_index(socket, socket.node)
),并返回一个邻居套接字。
现在,我构造了ShaderNodeCustomGroup
的子类(在下面的SUBCLASS中)。这个子类可以生成它的UI并具有套接字并完成节点可以执行的所有操作。它只是有几个我可以定义的附加功能。从这个类的方法,调用上面的函数。 SUBCLASS将其中一个套接字作为此函数的输入。然后该函数获取套接字的节点(这只是SUBCLASS本身)。这会使应用程序崩溃。
class LayerStackNode(bpy.types.ShaderNodeCustomGroup):
bl_label = "Layer Stack"
.
.
.
def insert_link(self, link):
# runs on the insert of a link,
# this is a preferred method when
# it gets repaired by blender devs
# check if the user is connecting mask
if link.to_socket.name == "mask_layer":
# simply draw a link from this socket to its mixer
my_index = mf.get_socket_index(link.to_socket, self)
relevant_layer = mf.get_socket_neighbor(link.to_socket, 1)
relevant_mixer = mf.get_node_by_type(self.node_tree.nodes, 'GROUP_INPUT').outputs[my_index - 1].links[0].to_node
self.node_tree.links.new(relevant_mixer.inputs[0], mf.get_node_by_type(self.node_tree.nodes, 'GROUP_INPUT').outputs[my_index])
return
def is_insert_input(self, link):
# determines whether the iserted link is input
if link.to_socket.name == 'layer':
return True
else:
return False
if not is_insert_input(self, link):
return
# if trying to insert on top of an empty layer, cancel and return
if mf.get_socket_neighbor(link.to_socket, -1) != mf.OUT_OF_RANGE and \
mf.get_socket_neighbor(link.to_socket, -1).is_NULL_layer:
# TODO: find a way to undo the operation
return
if self.is_NULL_layer(link.to_socket): # proceed only if it's empty
if not mf.get_socket_index(link.to_socket, self) == (len(self.inputs)-1): # <--- private case for the lowest layer in the stack
if not self.is_NULL_layer(mf.get_socket_neighbor(link.to_socket, -1)):
self.initialize_layer(link.to_socket)
else:
print("CANNOT MIX ONTO NULL LAYER")
else:
# when base layer, create a single link from input to output
sock_index = mf.get_socket_index(link.to_socket, self)
out = mf.get_node_by_type(self.node_tree.nodes, 'GROUP_INPUT').outputs[sock_index]
inp = mf.get_node_by_type(self.node_tree.nodes, 'GROUP_OUTPUT').inputs[0]
self.node_tree.links.new(inp, out)
else:
print("no action needed, the layer is not NULL")
.
.
.
与你相关的是mf.get_socket_neighbor(link.to_socket, -1).is_NULL_layer
。这里节点的类给出一个如果它的套接字到函数,然后它试图找到这个套接字的节点,这是调用类本身。
总而言之,SUBCLASS的方法为一个函数提供了SUBCLASS的套接字,然后该函数试图访问套接字节点,即SUBCLASS本身。如果我重新构建代码,以便函数只需要自己,并且不必访问socket.node,一切正常。
所以,我的问题是:这是循环参考吗?如果是的话,有没有办法克服它?我关心因为这使得使用类不太合理:例如,我无法定义访问其节点的套接字的属性。因为如果我在节点方法中使用此属性,这也会使应用程序崩溃。
这里没有明确显示或暗示的父/子关系。 B.A和A.B不建议父母/子女关系。他们只是说B包含属性名称'A'而A包含名为'B'的属性。这根本没有任何问题(除了命名约定)。这两个名字彼此无关,也与父母/子女关系无关。在B.A的情况下,'A'与名为'A'的类无关。
关于:
# random_function will reference A now, but not via self, is this a problem?
不,random_function不会引用A. random_function将引用A类的B属性包含的任何内容。