Python 类方法是否会引用类实例而不是通过自身导致circ依赖,以及如何应对它?
如果类B是a的子类,下面的代码会导致循环依赖吗? (为了简单起见,我不区分A,B和A(),B()) 我知道,这很容易解决Python 类方法是否会引用类实例而不是通过自身导致circ依赖,以及如何应对它?,python,circular-dependency,Python,Circular Dependency,如果类B是a的子类,下面的代码会导致循环依赖吗? (为了简单起见,我不区分A,B和A(),B()) 我知道,这很容易解决 def random_function(A,B): do_stuff(A, B) class A: def method(self): # get B b = A.B random_function(self, b) 。。。但是我想知道我是否仍然可以只保留一个参数的签名 如果这太抽象了,那么这就是
def random_function(A,B):
do_stuff(A, B)
class A:
def method(self):
# get B
b = A.B
random_function(self, b)
。。。但是我想知道我是否仍然可以只保留一个参数的签名
如果这太抽象了,那么这就是为什么我要问:在Blender中,有一个套接字类和一个节点类,其中套接字是节点的子类。我有一个子类node和一个函数,如下所示:
def func(socket):
# get parent
node = socket.node
do_stuff(node, socket)
class sub_class(Node):
def method(self):
func(self.Socket)
有没有一种方法可以让函数签名只包含一个参数,而不会在这里陷入循环依赖
编辑:提供一些实际代码和上下文的编辑,在注释中遵循建议
我将从我认为导致循环引用的类的描述开始
类ShaderNodeCustomGroup
表示一个节点—一种来自可视化编程的东西。它有套接字,它正在监听这些套接字上发生的事情。用户将输入连接到输入套接字,可以从输出套接字获取输出。基本上是非编程用户函数的可视化表示。虚幻也有这个,但我的是搅拌机
类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]
与您相关的是mf.get\u socket\u neighbor(link.to\u socket,-1)。is\u NULL\u layer
。
这里,节点的类为函数提供了一个if套接字,然后它试图找到这个套接字的节点,即调用类本身
总之,子类的方法将子类的套接字提供给一个函数,然后该函数尝试访问套接字的节点,即子类本身。如果我重新编译代码,使函数只接受self,而不必访问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_函数将不引用A。random_函数将引用A类的B属性包含的任何内容。我认为您关于不存在父/子关系的说法是正确的。另外,
random\u function()
引用了作为其B
参数传递给它的任何was参数的A
属性,该参数可能根本不是类。有了这段代码,您根本不知道发生了什么。这段代码本身当然不会运行。为了让它运行,必须定义A的“B”属性,不管是什么,它必须有一个名为“A”的属性。是的,不清楚OP到底在问什么——这就是为什么我自己没有尝试回答它(以及为什么我在之前的评论中说“思考”).我觉得我可以说点什么,因为OP显然认为A.B和B.A以某种方式表示父母/子女关系。我只是想指出那不是真的。谢谢你的回答。我在一开始就明确提到B是一个类。代码中定义了,因此它也是一个类。实际上,这是在应用程序运行时崩溃。对不起,这是一段抽象的代码,我会在一段时间内把它删掉。我为你在这方面再冒一次险而鼓掌。我明天再看我喜欢你用一个象征性的例子来保持简单的想法。也许你可以再试一次,但是试着从父/子、循环引用等方面体现你认为存在的问题。如果你能解释一下在实际遵循执行流程时你在哪里看到问题,那就太好了。我不想批评你的第一次尝试,然后不尽我所能帮助你。我真的觉得我需要这样做。计算机对我一直很好。想要回报……我可能需要你带我经历一下。@Steve听起来不错,谢谢。如果您对基础类和blender api有任何疑问,请随时提问。好的,我会在一段时间内对其进行几次编辑,然后你可以问还缺少什么,干杯@史蒂夫,我做了大量的编辑,但没有机会让它在任何程度上都可以理解,对不起。。。
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")
.
.
.
# random_function will reference A now, but not via self, is this a problem?