0

I'm building a simplified Blockchain app.
I built my own iterator, and it works.

Here is my code:

# ---------- DEPENDENCIES AND OTHERS ----------
import datetime
blockchains = []
n = 0

# ---------- BLOCK CLASS ----------
class Block:
    def __init__(self, sender, money, receiver, previous_block=None):
        self.time = datetime.datetime.now()
        self.sender = sender
        self.money = money
        self.receiver = receiver
        self.previous_block = previous_block

    def __repr__(self):
        return f"""> NEW BLOCK:
Time: {self.time}
Sender: {self.sender}
Money: {self.money}
Receiver: {self.receiver}
"""


# ----------BLOCKCHAIN CLASS ----------
class Blockchain:
    def __init__(self):
        # Set "Tail Block" default as none. This will help identify if Blockchain is empty or not.
        self.tail_block = None
        # Check if there are any existing blockchains
        if not blockchains:
            self.name = input("Insert New Blockchain Name: ")
            blockchains.append(self)
        else:
            # Cycle to ensure new Blockchain has a unique name.
            valid_name = False
            while not valid_name:
                name = input("Insert New Blockchain Name: ")
                print()
                if any(blockchain.name == name for blockchain in blockchains):
                    print("Name already in use.\n")
                else:
                    valid_name = True
                    self.name = name
                    blockchains.append(self)

    def __iter__(self):
        return self

    def __next__(self):
        # If Blockchain is empty:
        if not self.tail_block:
            raise StopIteration
        # If Blockchain is not empty:
        else:
            """ 'n' counts what iteration of "__next__()" the program is in.
                Or in other words, how many times the "__next__()" function has been run."""
            global n
            n += 1
            # If it's the first "__next__()" iteration:
            if n == 1:
                return self.tail_block
            # If it's after the first "__next__()" iteration:
            else:
                current_block = self.tail_block
                for i in range(n-1):
                    current_block = current_block.previous_block
                if not current_block:
                    raise StopIteration
                else:
                    return current_block

    def __repr__(self):
        return f"{self.name}"

    def add_block(self, new_block_sender, new_block_money, new_block_receiver):
        # Check to see if Blockchain is empty
        if not self.tail_block:
            new_block = Block(new_block_sender, new_block_money, new_block_receiver)
        # If it's not empty, the new block's "previous block" will be the existing "tail block"
        else:
            new_block = Block(new_block_sender, new_block_money, new_block_receiver, self.tail_block)
        # Update "Tail Block" to the newly created block
        self.tail_block = new_block

    def view(self):
        if not self.tail_block:
            print("There are no Blocks in this Blockchain.\n")
        else:
            current_block = self.tail_block
            while True:
                print(current_block)
                if not current_block.previous_block:
                    break
                else:
                    current_block = current_block.previous_block


# ---------- TESTS ----------
# Testing my iterator with an empty Blockchain:
blockchain_1 = Blockchain()
for block in blockchain_1:
    print(block)

# Testing my iterator with non empty Blockchain:
blockchain_2 = Blockchain()
blockchain_2.add_block("António", 200000, "Tim")
blockchain_2.add_block("António", 100000, "Bob")
blockchain_2.add_block("António", 50000, "John")
blockchain_2.add_block("António", 50000, "Bill")
for block in blockchain_2:
    print(block)

In my iterator, there's a variable called n.
I declare n right at the beginning of the program with n = 0 to make it a global variable.

So, since n a global variable, I just increment it inside my __next__() method with the code: n += 1.
However, when I do that, I get an UnboundLocalError: enter image description here

After experimenting, I found that if I type global n above n +=1 it fixes it: enter image description here But why?

Since I declared n = 0 at the beginning of the program, shouldn't n already be a global variable?
Why do I have to "re-global" n to make this work, when n was already supposed to be global in the first place?

  • you can declare it like this : global n – Ghassen Jul 03 '19 at 20:42
  • Next time you have a question, please reduce the code to a [mcve] **in text form**, too. – jonrsharpe Jul 03 '19 at 20:43
  • @jonrsharpe I know it's a lot, but it's hard to ask this question with little code, because it envolves a lot of methods and multiple classes. – António Gonçalves Jul 03 '19 at 20:45
  • No it doesn't; you're asking about `global`, which just needs a top-level variable and one place where you try to assign to it. *Your specific program* has a lot of other code, but that's not actually relevant. – jonrsharpe Jul 03 '19 at 20:46
  • I'd just point out that I'm not sure a global is actually an appropirate thing to use in this kind of code. When you're using classes, you usually should be interacting with instance variables, not globals. I don't actually understand your code well enough to fully assess it, but I'd guess that both `blockchains` and `n` should be instance variables that you initialize in `__init__` and access via `self.n` etc. – Blckknght Jul 03 '19 at 20:55

0 Answers0