【问题标题】:Python string indices must be integers - Python 3.x vs. 2.x?Python 字符串索引必须是整数 - Python 3.x 与 2.x?
【发布时间】:2018-03-14 01:47:36
【问题描述】:

我正在努力在 python 中重新创建一个区块链,虽然我的大部分代码都可以正常工作,但我不知道为什么这部分不可用。编码在 3.5 中是如何工作的?

原文:

from flask import Flask
from flask import request
import json
import requests
import hashlib as hasher
import datetime as date
node = Flask(__name__)

# Define what a Snakecoin block is
class Block:
  def __init__(self, index, timestamp, data, previous_hash):
    self.index = index
    self.timestamp = timestamp
    self.data = data
    self.previous_hash = previous_hash
    self.hash = self.hash_block()

  def hash_block(self):
    sha = hasher.sha256()
    sha.update(str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash))
    return sha.hexdigest()

# Generate genesis block
def create_genesis_block():
  # Manually construct a block with
  # index zero and arbitrary previous hash
  return Block(0, date.datetime.now(), {
    "proof-of-work": 9,
    "transactions": None
  }, "0")

# A completely random address of the owner of this node
miner_address = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi"
# This node's blockchain copy
blockchain = []
blockchain.append(create_genesis_block())
# Store the transactions that
# this node has in a list
this_nodes_transactions = []
# Store the url data of every
# other node in the network
# so that we can communicate
# with them
peer_nodes = []
# A variable to deciding if we're mining or not
mining = True

@node.route('/txion', methods=['POST'])
def transaction():
  # On each new POST request,
  # we extract the transaction data
  new_txion = request.get_json()
  # Then we add the transaction to our list
  this_nodes_transactions.append(new_txion)
  # Because the transaction was successfully
  # submitted, we log it to our console
  print "New transaction"
  print "FROM: {}".format(new_txion['from'].encode('ascii','replace'))
  print "TO: {}".format(new_txion['to'].encode('ascii','replace'))
  print "AMOUNT: {}\n".format(new_txion['amount'])
  # Then we let the client know it worked out
  return "Transaction submission successful\n"

@node.route('/blocks', methods=['GET'])
def get_blocks():
  chain_to_send = blockchain
  # Convert our blocks into dictionaries
  # so we can send them as json objects later
  for i in range(len(chain_to_send)):
    block = chain_to_send[i]
    block_index = str(block.index)
    block_timestamp = str(block.timestamp)
    block_data = str(block.data)
    block_hash = block.hash
    chain_to_send[i] = {
      "index": block_index,
      "timestamp": block_timestamp,
      "data": block_data,
      "hash": block_hash
    }
  chain_to_send = json.dumps(chain_to_send)
  return chain_to_send

def find_new_chains():
  # Get the blockchains of every
  # other node
  other_chains = []
  for node_url in peer_nodes:
    # Get their chains using a GET request
    block = requests.get(node_url + "/blocks").content
    # Convert the JSON object to a Python dictionary
    block = json.loads(block)
    # Add it to our list
    other_chains.append(block)
  return other_chains

def consensus():
  # Get the blocks from other nodes
  other_chains = find_new_chains()
  # If our chain isn't longest,
  # then we store the longest chain
  longest_chain = blockchain
  for chain in other_chains:
    if len(longest_chain) < len(chain):
      longest_chain = chain
  # If the longest chain isn't ours,
  # then we stop mining and set
  # our chain to the longest one
  blockchain = longest_chain

def proof_of_work(last_proof):
  # Create a variable that we will use to find
  # our next proof of work
  incrementor = last_proof + 1
  # Keep incrementing the incrementor until
  # it's equal to a number divisible by 9
  # and the proof of work of the previous
  # block in the chain
  while not (incrementor % 9 == 0 and incrementor % last_proof == 0):
    incrementor += 1
  # Once that number is found,
  # we can return it as a proof
  # of our work
  return incrementor

@node.route('/mine', methods = ['GET'])
def mine():
  # Get the last proof of work
  last_block = blockchain[len(blockchain) - 1]
  last_proof = last_block.data['proof-of-work']
  # Find the proof of work for
  # the current block being mined
  # Note: The program will hang here until a new
  #       proof of work is found
  proof = proof_of_work(last_proof)
  # Once we find a valid proof of work,
  # we know we can mine a block so 
  # we reward the miner by adding a transaction
  this_nodes_transactions.append(
    { "from": "network", "to": miner_address, "amount": 1 }
  )
  # Now we can gather the data needed
  # to create the new block
  new_block_data = {
    "proof-of-work": proof,
    "transactions": list(this_nodes_transactions)
  }
  new_block_index = last_block.index + 1
  new_block_timestamp = this_timestamp = date.datetime.now()
  last_block_hash = last_block.hash
  # Empty transaction list
  this_nodes_transactions[:] = []
  # Now create the
  # new block!
  mined_block = Block(
    new_block_index,
    new_block_timestamp,
    new_block_data,
    last_block_hash
  )
  blockchain.append(mined_block)
  # Let the client know we mined a block
  return json.dumps({
      "index": new_block_index,
      "timestamp": str(new_block_timestamp),
      "data": new_block_data,
      "hash": last_block_hash
  }) + "\n"

node.run()

我的版本如下。我收到的错误是:

“文件“davecoin.py”,第 113 行,在我的 last_proof = int(last_block.data['proof-of-work']) TypeError: 字符串索引必须是整数"

from flask import Flask
from flask import request
import json
import requests
import hashlib as hasher
import datetime as date
node = Flask(__name__)

class Block:
  def __init__(self, index, timestamp, data, previous_hash):
    self.index = index
    self.timestamp = timestamp
    self.data = data
    self.previous_hash = previous_hash
    self.hash = self.hash_block()

  def hash_block(self):
    sha = hasher.sha256()
    sha.update(str(self.index).encode('utf-8') + str(self.timestamp).encode('utf-8') + str(self.data).encode('utf-8') + str(self.previous_hash).encode('utf-8'))
    return sha.hexdigest()

def create_genesis_block():
    # Manually create the first block of davecoin. Index = 0.
    return Block(0, date.datetime.now(), {
        "proof-of-work": 7,
        "transactions": None
    }, "0")

miner_address = "34h5jk34h5-miner-address-k5j34h5634"
this_nodes_transactions = []

@node.route('/txion', methods=['POST'])
def transaction():
  # On each new POST request,
  # we extract the transaction data
  new_txion = request.get_json()
  # Then we add the transaction to our list
  this_nodes_transactions.append(new_txion)
  # Because the transaction was successfully
  # submitted, we log it to our console
  print("New transaction")
  print("FROM: {}".format(new_txion['from'].encode('ascii','replace')))
  print("TO: {}".format(new_txion['to'].encode('ascii','replace')))
  print("AMOUNT: {}\n".format(new_txion['amount']))
  # Then we let the client know it worked out
  return "Transaction sent successfully.\n"

def next_block(last_block):
    this_index = last_block.index + 1
    this_timestamp = date.datetime.now()
    this_data = "Davecoin Block " + str(this_index)
    this_hash = last_block.hash
    return Block(this_index, this_timestamp, this_data, this_hash)

blockchain = [create_genesis_block()]
previous_block = blockchain[0]

blocks_to_add_after_genesis = 15

for i in range(0, blocks_to_add_after_genesis):
    block_to_add = next_block(previous_block)
    blockchain.append(block_to_add)
    previous_block = block_to_add
    print("Block #" + str(block_to_add.index) +" has been added to the blockchain.")
    print("Hash: "+ block_to_add.hash)

@node.route('/blocks', methods=['GET'])
def get_blocks():
    chain_to_send = blockchain
    #Convert blocks to dictionary for json
    for block in chain_to_send:
        block_index = str(block.index)
        block_timestamp = str(block.timestamp)
        block_data = str(block.data)
        block_hash = block.hash
        block = {
            "index": block_index,
            "timestamp": block_timestamp,
            "data": block_data,
            "hash": block_hash
        }
        chain_to_send = json.dumps(chain_to_send)
    return chain_to_send

def find_new_chains():
    other_chains = []
    for node_url in peer_nodes:
        block = requests.get(node_url + "/blocks").content
        #convert json to python dictionary
        block = json.loads(block)
        other_chains.append(block)
    return other_chains

def consensus():
# get blocks from other nodes
    other_chains = find_new_chains()
    longest_chain = blockchain
    for chain in other_chains:
        if len(longest_chain) < len(chain):
            longest_chain = chain
    blockchain = longest_chain

def proof_of_work(last_proof):
    incrementor = last_proof + 1
    while not (incrementor % 7 == 0 and incrementor % last_proof == 0):
        incrementor += 1
    return incrementor

@node.route('/mine', methods = ['GET'])
def mine():
  # Get the last proof of work
  last_block = blockchain[len(blockchain) - 1]
  last_proof = last_block.data['proof-of-work']
  # Find the proof of work for
  # the current block being mined
  proof = proof_of_work(last_proof)
  # Reward miner for finding block
  this_nodes_transactions.append(
    { "from": "network", "to": miner_address, "amount": 1 }
  )
  # Gather data for new block
  new_block_data = {
    "proof-of-work": proof,
    "transactions": list(this_nodes_transactions)
  }
  new_block_index = last_block.index + 1
  new_block_timestamp = this_timestamp = date.datetime.now()
  last_block_hash = last_block.hash
  # Empty transaction list
  this_nodes_transactions[:] = []
  # Create new block
  mined_block = Block(
    new_block_index,
    new_block_timestamp,
    new_block_data,
    last_block_hash
  )
  blockchain.append(mined_block)
  # Let the client know we mined a block
  return json.dumps({
      "index": new_block_index,
      "timestamp": str(new_block_timestamp),
      "data": new_block_data,
      "hash": last_block_hash
  }) + "\n"

node.run()

【问题讨论】:

  • 这是什么? Python 2 还是 Python 3?不能两者兼有。
  • 我的是 Python 3.5。不知道如何找到原始版本,但这里是github code
  • 您确定为第二个程序复制了正确的文本吗? 它们完全相同。
  • 完全确定。我将两者都与代码差异工具进行了比较,以确保我没有遗漏任何内容。我仍然是 Python 的初学者,但实际上我唯一能想到的是这可能是一个问题,因为它们是不同版本的 python。
  • 等一下……你知道代码示例是一样的吗?你有什么问题?

标签: python json python-3.x flask


【解决方案1】:

假设data 是json,在__init__ 中执行以下操作:

self.data = json.loads(data)

希望这行得通。

【讨论】:

  • 嗨法哈特。它是 json,但是在添加并删除 'self.data = data' 时我得到以下信息:“TypeError:JSON 对象必须是 str,而不是 'dict'”
  • 你能不能这样做print type(last_block.data) 让我知道输出是什么?
  • 很高兴,但在测试 python 代码时,我还是个初学者。我知道如何在常规 python 终端中执行此操作,但我不确定如何在文件的类或函数中运行 print type(last_block.data)。鉴于我上面的代码,你会在哪里插入它或者你会使用 python 命令?如果这很重要,我会在 notepad++ 和 github shell 中完成所有这些操作。
  • @node.route('/mine', methods = ['GET']) 路线中进行。将 print 语句放在 mine() 的第一行。完成后,点击该端点并在终端中查看print 输出。
  • 知道了。谢谢。 :) 由于 python 3.5 打印语法以及创建 last_block 时,我必须按以下方式进行操作:@node.route('/mine', methods = ['GET']) def mine(): # Get the last proof of work last_block = blockchain[len(blockchain) - 1] print(type(last_block.data)) last_proof = last_block.data['proof-of-work'] 仍然遇到相同的错误,但不是在返回 &lt;class 'str'&gt; 之前
猜你喜欢
  • 2020-08-04
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2016-03-26
  • 2016-02-17
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多