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

2024-05-23 16:13:47 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我的神经元课

  1. 枝晶
    初始化类时,树突的数量在参数中指定。树突存储在一个列表中,该列表的索引存储每个树突的电压。 例如:neuron1.dendrites[2]=0.12
  2. 激活(阈值)电位 所有树突电位的总和提供了神经元电位。如果这个电位超过阈值电位,我的神经元就会启动。还有其他神经元连接到我神经元的轴突上。我的神经元轴突与其他神经元对象的树突相连。其他神经元的几个树突可能连接到我神经元的轴突上。当我的神经元启动时,它们都会收到一个固定的电压(输出电压)。它以全有或全无的方式开火
  3. 点火状态
    当达到激活电位时,点火状态=开(真)
  4. 我的Neuron类还有一个setConnections()方法。此方法接收树突的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()方法得到更新。有人能解释一下原因吗?原谅我,我是一个Python新手


Tags: andoftheselfdefactivation电位pot
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数组(存储外部树枝晶电压列表)正在更新,而树枝晶本身没有更新

经过一些研究和实验,我终于解决了这个难题。首先是一些necessary background reading

All Python objects have:

  1. a unique identity (an integer, returned by id(x))
  2. a type (returned by type(x))
  3. some content

You cannot change the identity!

You cannot change the type!

Some objects allow you to change their content (without changing the identity or the type, that is). These are mutable data types and include 'list's for example

Most objects do not (eg: string, integer, tuple, etc...)

我最后得出结论:

  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))


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

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

可能不是最好的解决方案,但只是我的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]

相关问题 更多 >