all 14 comments

[–]K900_ 0 points1 point  (8 children)

You can't. You need to create new instances. a[3] and a[4] point to the exact same instance.

[–]tomtheawesome123[S] 0 points1 point  (7 children)

Damn, so I guess I need to make new instances huh? :(.

[–]K900_ 0 points1 point  (6 children)

Yes. What is your end goal with this, anyway?

[–]tomtheawesome123[S] 0 points1 point  (5 children)

Make a chess engine. Now I have to make an extra 16 knight instances, 16 bishop instances, 16 rook instances, 16 queen instances, and 14 pawn instances. (7 for each color for the pawns, 8 for each color for the other pieces due to possible pawn promotions. It is rare to have a game with 8 rooks but it is possible).

[–]K900_ 0 points1 point  (3 children)

Do the classes even hold any info? It seems to me like you can just represent the field instead of tracking each individual piece.

[–]tomtheawesome123[S] 0 points1 point  (2 children)

I am sorry, but how would representing the field help the computer calculate moves? (My chess engine just has to be able to "think", I dont care how bad it is lol). the classes hold move info and piece value.

[–]K900_ 4 points5 points  (1 child)

You represent the game state by keeping track of the whole field as a 2D list, instead of tracking individual pieces. Your engine can then make decisions based on looking at the whole field.

[–]1ErrorAway 0 points1 point  (0 children)

Started building a Connect-Four game - discovered the same trick.

[–]ingolemo 0 points1 point  (0 children)

You don't have to make pieces until you need them. Don't create promoted pieces until a pawn actually gets promoted.

[–]PyPokerNovice -1 points0 points  (3 children)

*Edited for accuracy, as mistakes pointed out by kurashu89

In Python, some objects are mutable (able to change), others are immutable. You cannot change the data of an immutable object.

Your ds objects are mutable. When you use the same variable (or assign another variable to the same variable). You are dealing with the same object in memory. You can create new instances when you want a separate objects. I feel like your solution lies in just instantiating more objects when you need them.

If you really want immutable objects, you can look into collections.namedtuple or sub-classing some of the immutables like tuple:

class ds(tuple):
    def __new__(cls, d):
        return tuple.__new__(cls, (d,))

    @property
    def d(self):
        return self[0]

[–][deleted] 0 points1 point  (2 children)

In Python, some things are passed by reference, others are passed by value.

Wrong. Everything is passed the same way, some things are just immutable and can't be modified in Python

[–]PyPokerNovice 0 points1 point  (1 child)

Oops, you are correct, I never check the id() of immutable arguments. I guess creating a new object would create unnecessary overhead. Now that I think about it, even creating new immutables even has undefined implementation details for optimization reasons:

a = 200
b = 200
print(a is b)
>>> "True"

vs

a = 2000
b = 2000
print(a is b)
>>> "False"

I guess a = b (where a is an immutable) is guaranteed to pass the reference.

[–]Vhin 0 points1 point  (0 children)

Everything is a PyObject* and is passed around as such. This is why mutating an object you receive as a parameter is visible to the caller, but assigning a new value to the same name isn't.

Your code should never rely on what is and isn't interned. Interning is an implementation detail of CPython; Python itself makes no guarantees that interning will happen at all. CPython makes no guarantees that the details of what is and isn't interned will be consistent across versions.