python __setattr__ causes attribute error on a defined variable - python-3.x

Every time the 'setattr' magic method is called it causes an attribute error for some reason. I'm getting an attribute error saying the 'rect' variable doesn't exist but it's clearly defined in the class.
import pygame as pg
class Block:
blocks = {}
id_ = 1
def __init__(self, surface, name=None, color=[0] * 3, width=0):
self.surface = surface
self.name = (name if name else Block.id_)
self.color = color
self.width = width
self.rect = pg.Rect((0, 0), [20] * 2)
self.block = self.make_block()
pg.draw.polygon(*self.block)
Block.blocks[self.name] = self
if not name:
Block.id_ += 1
def make_block(self):
point_1 = self.rect.topleft
point_2 = (self.rect.topleft[0], self.rect.topleft[1] + self.rect.size[1])
point_3 = (point_2[0] + self.rect.size[0], point_2[1])
point_4 = (point_3[0], point_1[0])
return [self.surface, self.color, (point_1, point_2, point_3, point_4), self.width]
def __setattr__(self, name, value):
pass
Block(pg.Surface((20, 20)))

You overrode __setattr__ to do nothing. That is where the attribute would be set. Take this small example:
In [3]: class Rect:
...: def __init__(self):
...: self.length = 12
...: self.width = 5
...: def __setattr__(self, name, val):
...: print(f"attempting to set {name}={val}")
...:
In [4]: r=Rect()
attempting to set length=12
attempting to set width=5
In [5]: r.length
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-1697af2cfc88> in <module>
----> 1 r.length
AttributeError: 'Rect' object has no attribute 'length'
Because I override it and don't actually set it, there's no attributes being set for my class. So when I try to access it, it will cause an error. I'm guessing that is what you're experiencing. If you want to fix that then you need to set the attribute when you override it and not just pass.

Related

Super() class's attributes not inherited?

It seems the child class doesn't inherit the parent attributes, despite calling super().__init__(args).
I read
Python: subclass inherits super class attributes, but loses it's other attributes
and
Subclass is not inheriting the attributes of second Super Class
but I read the attributes should be inherited if called within super().__init__()
With the following code (3.10.1)
class interface(object):
MEDIA = ('COPPER','FIBER')
SPEED_COPPER = ('100', '1G', '2.5G', '5G', '10G')
SPEED_FIBER = ('10G', '25G', '40G', '100G')
TYPE_L2 = ('ACCESS', 'TRUNK', 'HYBRID')
def __init__(self, media = None, speed = None):
self.media = media
self.speed = speed
def set_media(self):
pass
def is_copper(self):
return self.media == 'COPPER'
def is_fiber(self):
return self.media == 'FIBER'
class copper_1G(interface):
def __init__(self):
super().__init__(media = 'COPPER', speed = '1G')
class generic_mod(object):
def __init__(self, max_slots):
self.slots = []
self.max_slots = max_slots
self.set_interfaces()
def set_interfaces(self):
if len(self.slots) < self.max_slots:
for slot in range(0,self.max_slots):
self.slots.append(copper_1G)
class module48_2(generic_mod):
MAX_SLOTS = 48
def __init__(self):
super().__init__(self.MAX_SLOTS)
self.set_interfaces()
>>> ff=module48_2()
>>> ff.slots[0].media
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'copper_1G' has no attribute 'media'
>>> ff.slots[0].speed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'copper_1G' has no attribute 'speed'
the variable ff.slots[0] doesn't get the attributes media and speed of the parent class, though it gets the methods is_copper, is_fiber, etc etc...
class generic_mod(object):
...
def set_interfaces(self):
if len(self.slots) < self.max_slots:
for slot in range(0,self.max_slots):
self.slots.append(copper_1G)
self.slots.append(copper_1G) -> self.slots.append(copper_1G())

How to code my own dot product using a Python class?

I want to create a subclass of numpy adding a new method. Here is my first step:
class MyNumpy(np.ndarray):
def __init__(self):
np.ndarray.__init__(self)
def my_inner(self, x, y):
dotpr = 2*x[0]*y[0] + 3*x[1]*y[1]
return dotpr
Obviously my_inner() is wrong, but I wrote it here to show what I want.
Commenting out my_inner(), and typing in
p = MyNumpy([0.1, 0.2])
print("type(p): ", type(p))
p
the error message is produced
TypeError Traceback (most recent call last)
<ipython-input-54-2cee31ae802a> in <module>
----> 1 p = MyNumpy([0.1, 0.2])
2 print("type(p): ", type(p))
3 p
TypeError: 'float' object cannot be interpreted as an integer
I don't know what this 'float' object refers to here. Any help?
Thanks!
As #Quang Hoang pointed out, when you initiate the np.ndarray you pass it a shape, and it should be of type int, like:
class MyNumpy(np.ndarray):
def __init__(self, shape):
super().__init__()
def my_inner(self, x, y):
dotpr = 2*x[0]*y[0] + 3*x[1]*y[1]
return dotpr
p = MyNumpy((2, 6))
print("type(p): ", type(p))
p
cheers.

Question about deck of cards using OOP python

This is the current code:
import random
class Cards():
def __init__(self, value, suit):
self.value = value
self.suit = suit
def show(self):
print("{} of {}".format(self.value, self.suit.upper()))
class Deck():
def __init__(self):
self.cards = []
self.build()
def build(self):
suits = ['Spades', 'Hearts', 'Clubs', 'Diamonds']
for suit in suits:
for value in range(1,14):
self.cards.append(Cards(value,suit))
def show(self):
for card in self.cards:
card.show()
def shuffle(self):
for i in range(len(self.cards)-1, 0, -1):
rand = random.randint(0, i)
self.cards[i], self.cards[rand] = self.cards[rand], self.cards[i]
def draw(self):
return self.cards.pop()
deck = Deck()
deck.shuffle()
deck.draw().show()
The OOP part still confuses me, so excuse my elementary question but how come I can do deck.draw().show() but not deck.shuffle().draw().show()?
What I mean is that when I keep deck.shuffle() AND THEN do deck.draw().show() it returns to me random cards. So what if I just wanted to do deck.shuffle().draw().show()? Why does it give me an error of
Traceback (most recent call last):
File "c:\Users\Desktop\deckofcards.py", line 40, in <module>
deck.shuffle().draw().show()
AttributeError: 'NoneType' object has no attribute 'draw'
PS C:\Users\learning_log>
You can get that behaviour with one small change:
def shuffle(self):
for i in range(len(self.cards)-1, 0, -1):
rand = random.randint(0, i)
self.cards[i], self.cards[rand] = self.cards[rand], self.cards[i]
return self # <- return a reference to the deck itself
Demonstration:
In [95]: deck.shuffle().draw().show()
8 of HEARTS
The reason you were getting that error is that you weren't returning anything from shuffle().
You can't do deck.shuffle().draw().show() because as the error says, deck.shuffle() is a nonetype, that means it has no value, because shuffle() does some stuff, it doesn't return anything so you are esentially doing 'nothing'.draw().show(). To solve it you could return something, just like other answer said you could return a reference to the deck.

python3 subclass is being instantiated as superclass, subclass method not found throwing AttributeError

I am attempting to define and instantiate a subclass in python3, but when calling a method on the subclass it throws an AttributeError, much as if I instantiated the object as an instance of the superclass; the method cannot be found. As far as I can tell, I have written the subclass constructor appropriately, calling the super() method without arguments as shown. Any help would be greatly appreciated.
Code used to instantiate subclass and call method:
class Player:
hands = []
...
def __init__(self):
...
def __deal(self, twocards):
self.hands = [Hand(showfirst=True)]
self.hands[0] += twocards
self.hands[0].showcards()
...
Definition of Hand class:
class Hand(pydealer.Stack):
def __init__(self, showfirst, **kwargs):
super().__init__(**kwargs)
stay = False
self.showfirstcard = showfirst
...
def showcards(self):
for i, card in enumerate(self):
if i == 0:
if self.showfirstcard == False:
print('***FACEDOWN CARD***')
else:
print(card)
Stacktrace and error message:
Traceback (most recent call last):
File "/root/python/django_webapp/mysite/webapp/blockjack/src/test.py", line 8, in <module>
table.start()
File "/root/python/django_webapp/mysite/webapp/blockjack/src/table.py", line 23, in start
self.dealer.deal(self.shoe.deal(2))
File "/root/python/django_webapp/mysite/webapp/blockjack/src/dealer.py", line 15, in deal
self.seecards(0)
File "/root/python/django_webapp/mysite/webapp/blockjack/src/player.py", line 39, in seecards
self.hands[whichhand].showcards()
AttributeError: 'Stack' object has no attribute 'showcards'
TL;DR: Why does it think I am trying to call a method on a parent class object (Stack) when I explicitly defined the object in question using Hand()?
EDIT: Added all relevant code undigested below:
test.py
import table
from pydealer import Deck
table = table.Table()
table.start()
table.py
from pydealer import Deck
from player import Player
from dealer import Dealer
class Table:
shoe = None
dealer = None
player = None
def __init__(self):
self.shoe = Deck()
self.shoe.rebuild = True
self.shoe.shuffle()
self.player = Player()
self.dealer = Dealer()
def start(self):
self.player.bet()
self.dealer.deal(self.shoe.deal(2))
self.player.deal(self.shoe.deal(2))
dealer.py
from player import Player
from hand import Hand
class Dealer(Player):
def __init__(self):
super().__init__()
def deal(self, twocards):
self.hands = [Hand(showfirst=False)]
self.hands[0] += twocards
self.seecards(0)
player.py
from hand.py import Hand
class Player:
hands = []
__chips = None
__betamount = None
def __init__(self):
self.__chips = 5000
def bet(self):
type(self.__betamount)
def __deal(self, twocards):
self.hands = [Hand(showfirst=True)]
self.hands[0] += twocards
self.hands[0].showcards()
def hit(self, card, whichhand):
self.hands[whichhand] += card
def stay(self, whichhand):
self.hands[whichhand].setstay()
def printscore(self, whichhand):
print(self.hands[whichhand].stackscore())
hand.py
import pydealer
class Hand(pydealer.Stack):
stay = None
showfirstcard = None
bust = None
def __init__(self, showfirst, **kwargs):
super().__init__(**kwargs)
stay = False
self.showfirstcard = showfirst
def stackscore(self):
total = 0
for card in self:
total += self.__bjval(card)
if total > 21:
for card in self:
if card.value == "Ace":
total -= 10
if total <= 21:
break
return total
def __bjval(self, card):
return {
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
'10': 10,
'Jack': 10,
'Queen': 10,
'King': 10,
'Ace':11
}[card.value]
#def receive(self, cards):
#self += cards
def setstay(self):
self.stay = True
def getsize(self):
return self.size()
def showcards(self):
for i, card in enumerate(self):
if i == 0:
if self.showfirstcard == False:
print('***FACEDOWN CARD***')
else:
print(card)
Figured it out. The object was not being instantiated as a Stack but was actually being converted to a stack upon the result of the += operator. The code for this operator instantiates and returns new stack object and the reference to the Hand object is lost altogether. Within stack.py:
def __add__(self, other):
try:
new_stack = Stack(cards=(list(self.cards) + list(other.cards)))
except:
new_stack = Stack(cards=(list(self.cards) + other))
return new_stack
I guess the only other way to go about this is to make the Hand class contain a Stack, since overriding the basic functionality of the superclass in this way seems to defeat the purpose of inheritance altogether?

Using variables in __init__ method in Python

I have been given a Python module where I have a class named 'Node'. The __init__ method inside the class is given below:
def __init__(self, data = None, next = None):
self.fata = data
self._next = next
I want to know how this would differ if I simply mention data and next as variables and don't assign them to None? Like this:
def __init__(self, data, next):
self.fata = data
self._next = next
If
class A:
def __init__(self, data = None, next = None):
self._data = data
self._next = next
class B:
def __init__(self, data, next):
self._data = data
self._next = next
Then, e.g.:
>>> x = A(1,2)
>>> y = B(1,2)
>>> #no difference so far, but
>>> z = A()
>>> w = B()
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
w = B()
TypeError: __init__() missing 2 required positional arguments: 'data' and 'next'
Missing required arguments are a run-time error. They don't default to None.

Resources