在python中,可以通过引用在参数中传递列表中的变量吗



我正在尝试创建一个由连接在一起的神经元对象组成的神经网络类。

我的神经元类有

  1. 枝晶
    初始化类时,参数中指定了枝晶的数量。树枝状物存储在列表中,该列表的索引存储每个树枝状物的电压。例如:neuron1.dendrites[2]=0.12
  2. 激活(阈值)电位所有树突电位的总和提供神经元电位。如果这个电位超过阈值电位,我的神经元就会启动。还有其他神经元连接到我神经元的轴突上。我的神经元的轴突与其他神经元对象的树突相连。来自其他神经元的几个树突可能连接到我的神经元的轴突。当我的神经元启动时,它们都会收到一个固定的电压(outputVoltage)。它以要么全有要么全无的方式开火
  3. 点火状态
    当达到激活电位时,点火状态=开启(True)
  4. 我的Neuron类还有一个setConnection()方法。该方法接收一个树状结构的pythonlist。在这个方法中,我希望遍历外部树枝状体的内部列表,并重置它们的电压值这不起作用。我不明白为什么,所以在这里寻求帮助

我在下面提供了我的代码的精简版本:

import threading

class Neuron:
def __init__(self, dendrites, activation_Pot=0.24):
"""
Create a dendrites[] array.
Each element of this array represents the voltage of that dendrite.
We can then loop through the array to sum up the signal strength.  
If the signal strength exceeds the Activation potential, then the all-or-nothing threshold has been breached and
we can transmit our signal along the axon.
"""
self.dendrites = [0]*dendrites
self.InputPotential = 0  # This variable will store the sum of all the dendrite voltages.  It is being initialised here.
self.activation_Pot = activation_Pot
self.on = True
self.off = False
self.voltsOut = 0.12      # This constant dictates the potential of the axon when the neuron is firing.
self.outputPotential = 0  # This variable  SETS the potential of the single axon when the threshold activation potential of the  neuron has been reached and the neuron is firing.
self.firing = self.off
self.axonConnections = []

# Launch a thread to check on a timer the sum of all dendrite inputs and fire when output > Activation Potential.
t1 = threading.Thread(target = self.start, args=[])
t1.start()


def fire(self):
self.outputPotential = self.voltsOut
self.firing = self.on
print("Neuron is firing!")

for outputDendrites in self.axonConnections:
outputDendrites = self.outputPotential

def stopFiring(self):
self.outputPotential = 0
self.firing = self.off
print("Neuron has STOPPED firing!")


def setActivation_Pot(self, activation_Pot):
if (activation_Pot >= 0) and (activation_Pot <=1):
self.activation_Pot = activation_Pot
else:
print("activation_Pot value needs to be between 0 and 1")
print("activation_Pot has not been reset.")
print("Please consider re-inputting a valid value.")        


def getActivation_Pot(self):
return self.activation_Pot


def setAxonConnections(self, axonConnections):
self.axonConnections = axonConnections

def getAxonConnections(self):
return self.axonConnections


def start(self):
while True:
while True:
self.InputPotential = 0  
for dendrite in self.dendrites:
self.InputPotential+=dendrite

if self.InputPotential >= self.activation_Pot:
self.fire()
break
while True:
self.InputPotential = 0
for dendrite in self.dendrites:
self.InputPotential+=dendrite

if self.InputPotential < self.activation_Pot:
self.stopFiring()
break

以下是测试Neuron类的main.py脚本中的相关代码:

from neuron import Neuron
# Instantiate transmitting neurone...
n0 = Neuron(3, 0.36)
# Instantiate receiving neurones...
n1 = Neuron(3, 0.36)
n2 = Neuron(3, 0.36)
n3 = Neuron(3, 0.36)
# Make the connections: I do this by creating storing my external Dendrites into a list 
# and passing that list to the transmitting neuron for it to update the voltages 
# of each of these neurons.  BUT THESE LIST VARIABLES ARE NOT GETTING UPDATED...
axonConns = [n1.dendrites[0], n2.dendrites[1], n3.dendrites[2]]
n0.setAxonConnections(axonConns) # THE LIST VARIABLES OF THE axonConns LIST ARE NOT GETTING UPDATED!!
n0.fire()  # THE LIST VARIABLES OF THE axonConns LIST ARE NOT GETTING UPDATED by this fire() method!!

我希望这是有道理的。总之:我将在n0.setAxonConnections(axonConns)行传递main.py脚本中的变量列表。我的Neuron类的neuron.fire()方法不会更新此列表中的变量。有人能解释一下原因吗?原谅我,我是个蟒蛇新手!

可能不是最好的解决方案,但只是我的2c。如果你想让其他神经元的树突也更新,你可以这样声明连接:

axonConns = [(n1.dendrites, 0), (n2.dendrites, 1), (n3.dendrites, 2)]

您需要传递枝晶本身的列表,并通过索引定义连接中要考虑的枝晶。然后更改fire方法以将索引考虑在内:

def fire(self):
self.outputPotential = self.voltsOut
self.firing = self.on
print("Neuron is firing!")

for dendrites, index in self.axonConnections:
dendrites[index] = self.outputPotential

编辑:

为了证明为什么OP的答案不足以更新fire()之外的神经元

In [1]: x = [1, 2, 3]
...:
...: def foo(val):
...:     potential = 100
...:     for i in range(len(val)):
...:         val[i] = potential
...:     return val
...:
...: print(x)
...: print(foo([x[0], x[1], x[2]]))
...: print(x)
...:
[1, 2, 3]
[100, 100, 100]
[1, 2, 3]

通过在python中玩以下代码,我认为我找到了一个解决方案:

def changeListVars(n):
for i in range(len(n)):
n[i] = n[i]+5
print()
print(n)
x=1
y=2
z=3
m = [x,y,z]
print(len(m))
for i in range(len(m)):
print (m[i])

changeListVars(m)
print()
print(m)

上述输出为:

3
1
2
3
[6, 7, 8]
[6, 7, 8]

起初,这似乎奏效了。因此,为了修复我的代码,我修改了两行:

for i in range(len(self.axonConnections)):
self.axonConnections[i] = self.outputPotential

所以我的新fire()方法如下所示:

def fire(self):
self.outputPotential = self.voltsOut
self.firing = self.on
print("Neuron is firing!")

for i in range(len(self.axonConnections)):
self.axonConnections[i] = self.outputPotential

上述实验的结果清楚地表明,python在参数中传递时,默认情况下确实通过引用传递列表中的变量。

但是(感谢@bdbd)我发现列表中的元素保持不变。例如,

print(x, y, z)

产生

1 2 3

这也意味着,在我的代码中,当axonConn阵列(存储外部枝晶电压的列表)得到更新时,枝晶本身没有得到更新。

经过一些研究和实验,我终于解决了这个难题。首先是一些必要的背景阅读:

所有Python对象都有:

  1. 一个唯一标识(一个整数,由id(x)返回)
  2. a类型(由类型(x)返回)
  3. 一些内容

您不能更改身份!

您不能更改类型!

某些对象允许您更改其内容(而不更改身份或类型)。这些是可变的数据类型包括"列表",例如

大多数对象没有(例如:stringintegertuple等)

我终于得出结论:

  1. python总是通过引用

  2. 但是,某些数据类型是不可变的(字符串、整数等)

  3. 当对它们的引用被传递给函数时;对这些变量的任何操作都需要对变量进行复制,以存储操作的结果。

  4. 变量的任何重复都会导致创建一个指向新值的新引用。这在这里解释得很好。

  5. 因此,当这种情况发生时,调用函数将不再看到被操纵的结果。这是因为无法重新分配调用函数参数的引用以指向新引用。一旦必须复制变量的内容,调用函数就不再将其视为新内容具有新引用。

  6. 这意味着像list这样的变量可以被附加并保留相同的引用——因此看起来就像它们是通过引用传递的。

  7. 但是,像stringsintegers这样的免疫表在操作后将丢失它们的引用,因为必须使用该新值创建新对象(例如stringinteger)。新对象将始终具有新引用因此,在这些场景中,函数调用将表现为,就好像它被值传递了一样

我在下面提供了一些代码,很好地说明了这一点:

'''
The results of this block of code suggest that python passes by value.
However, in truth, the output of the code PROVES a reference is passed!
But because the variable's data type is immutable, a new object is created within the function with a NEW reference.
The upshot of this being, behaviour which seems to show that the argument is passed by value, when this is not strictly the case.
'''
# EXAMPLE 1:
class PassByReference:
def __init__(self):
self.variable = 1
print("BEFORE function call, self.variable = " + str(self.variable))
print("BEFORE function call, id(self.variable) = " + str(id(self.variable)))
self.change(self.variable)
print("AFTER function call, self.variable = " + str(self.variable))
print("AFTER function call, id(self.variable) = " + str(id(self.variable)))
def change(self, var):
print("INSIDE modifying function, var TO BE incremented!  id(var) BEFORE incrementing = " + str(id(var)))
var = var + 1
print("INSIDE modifying function, var incremented!  Now, var = " + str(var))
print("INSIDE modifying function, AFTER var incremented!  id(var) AFTER incrementing = " + str(id(var)))
p = PassByReference()

以下是进一步的例子,证明了相同的发现:

'''
The results of all the examples below suggest that python passes by value.
However, in truth, the output of each block of code PROVES a reference is passed!
Where the variable data type is immutable, a new object is created within the function with a NEW reference.  The upshot of this being, behaviour which seems to show that the argument is passed by value, when this is not strictly the case.
Where the data type is mutable, the output clearly identifies that the arguments have been passed by reference and have been successfully mutated without losing their object reference so that "By Reference" behaviour manifests.
'''
# EXAMPLE 2:
def changeListVars2(n):
print("From inside the function, BEFORE incrementing n, id(n) = " + str(id(n)))
n = n + 5
print("From inside the function, n = " + str(n))
print("From inside the function, AFTER incrementing n, id(n) = " + str(id(n)))
m = 1
print("Before function call, m = " + str(m))
print("id(m) = " + str(id(m)))

changeListVars2(m)
print("After function call, m = " + str(m))
print("id(m) = " + str(id(m)))

# EXAMPLE 3:
def changeListVars(n):
for i in range(len(n)):
n[i] = n[i]+5
print("From inside the function, n = " + str(n))
x = 1
y = 2
z = 3
m = [x, y, z]
print("Before function call, m = " + str(m))
print("id(x) = " + str(id(x)))
print("id(m) = " + str(id(m)))

changeListVars(m)
print("After function call, m = " + str(m))
print("After function call, id(m) = " + str(id(m)))
print("After function call:  [x=" + str(x) + ", y=" + str(y) + ", z=" + str(z) + "]")
print("After function call, id(x) = " + str(id(x)))

print() #a new line to seperate output from the two blocks of code
print() #a new line to seperate output from the two blocks of code
print("ChangeListVars2:")

# EXAMPLE 4:
def swap(a, b):
x = a
print ("id(x) = " + str(id(x)))
print ("id(a) = " + str(id(a)))
print ("id(b) = " + str(id(b)))
a = b
print ("id(a) = " + str(id(a)))
b = x
print ("id(b) = " + str(id(b)))
a[0]= '20'


var1 = ['1','2','3','4']
var2 = ['5','6','7','8','9']
print ("id(var1) = " + str(id(var1)))
print ("id(var2) = " + str(id(var2)))
print()
swap(var1, var2)
print()
print ("id(var1 = )" + str(id(var1)))
print ("id(var2 = )" + str(id(var2)))
print ("var1 = " + str(var1))
print ("var2 = " + str(var2))

您没有在类方法中正确地重新分配outputEnd的值。

def fire(self):
self.outputPotential = self.voltsOut
self.firing = self.on
print("Neuron is firing!")
# Store the axonConnections into a temporary list for parsing since we'll be changing the values WHILE interating
initial_axonConnections_list = self.axonConnections
for index, outputDendrites in enumerate(initial_axonConnections_list):
outputDendrites = self.outputPotential
# We have stored the value in outputDendrites, but we're not doing anything with it, we have to assign it
self.axonConnections[index] = outputDendrites

最新更新