update the value of an empty attribute class using a method - python

Does anyone know how to update the value of an empty class instance in a method? My code does not work as expected.
class addition:
def __init__(self):
self.number = None
def add(self, data):
if self.number == None:
print('no')
self.number = data
else:
print('yes')
self.number + 10
return self.number
addition().add(4)
addition().add(5)
With addition().add(5) I want self.number to be equal to 4 but it stays equal to none. Please help!

You should either instantiate an object of your class or use a class method.
When you use a non static class, the members of your class receive the self identifier, meaning that they belong to that specific instance, that needs to be created. Like:
class addition:
def __init__(self):
self.number = None
def add(self, data):
if self.number == None:
print('no')
self.number = data
else:
print('yes')
self.number + 10
return self.number
addition1 = addition()
addition1.add(4)
addition1.add(5)
Otherwise, you can use a variable as a member of the class itself and declare the method a class method, then you don't need to instantiate an object and can call it directly. With a class method you don't use the word self, because you don't have an instance. Instead, you use (by convention) the word cls, referring to the class. Example:
class addition:
number = None
#classmethod
def add(cls, data):
if cls.number == None:
print('no')
cls.number = data
else:
print('yes')
cls.number + 10
return cls.number
addition.add(4)
addition.add(5)

Related

Parameter self unfilled, but when I fill it it gives expected type ' ' but got 'Type[]' warning

class Player:
def __init__(self):
self.godHole = GodHole
self.pits = []
for i in range(0, 6):
self.pits.append(Pit())
def return_stones(self):
return self.godHole.return_stones(self.godHole)
#or return self.godHole.return_stones()
# same warning for invoking seld.godHole.increment_stones()
class GodHole:
def __init__(self):
self.stones = 0
def return_stones(self):
return self.stones
def change_stones(self, s):
self.stones = s
def increment_stones(self):
self.stones += 1
When using the commented line I get self unfilled warning. when I used the first one I get the expected type ' ' but got 'Type[]' warning
What am I doing wrong? How can I fill self parameter? Can I even access instance attributes this way?
The attribute godHole of class Player, it is just a class, and no instantiation operation is performed, you directly use the instance method return_stones below, and pass in the class GodHole, which is wrong.
There are two ways to execute instance methods:
call directly using the class instance
when a class uses an instance method, the instance is passed in as a parameter
class Player:
def __init__(self):
self.godHole = GodHole()
self.pits = []
for i in range(0, 6):
self.pits.append(Pit())
def return_stones(self):
return self.godHole.return_stones()
or
class Player:
def __init__(self):
self.godHole = GodHole
self.pits = []
for i in range(0, 6):
self.pits.append(Pit())
# def return_stones(self):
# return self.godHole.return_stones(self.godHole())
def return_stones(self, obj: GodHole):
# obj is an instance object of class GodHole
return self.godHole.return_stones(obj)

Assign two functions to class?

class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
return self.number + add_num
def sub(self, sub_num):
return self.number - sub_num
Math(5).add(5)
I get 10 as expected
But if I do Math(5).add(5).sub(3):
I get this error AttributeError: 'int' object has no attribute 'sub'
for that to work your mehtods need to return self (or a fresh instance of Math):
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
self.number += add_num
return self
# or:
# return Math(self.number + add_num)
def sub(self, sub_num):
self.number -= sub_num
return self
# or:
# return Math(self.number - add_num)
def __str__(self):
return str(self.number)
m = Math(5).add(5).sub(3)
print(m)
# 7
the add here now behaves more like an __iadd__.
Of course.
What you do is essentially
a = Math(5) # a is a "Math" object
b = a.add(5) # b is what add() returns, i. e. an int
c = b.sub(3) # an int has no sub() method
I don't know what exactly you want to achieve: do you want add() and sub() to modify the object you are operating on? In this case, you can do
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
self.number = self.number + add_num
return self
def sub(self, sub_num):
self.number = self.number - sub_num
return self
If you don't want that, you can do instead
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
return Math(self.number + add_num)
def sub(self, sub_num):
return Math(self.number - sub_num)
return self
In both cases, your intended way of chaining the calls works.
The value that you return is not an object of your Math class.
You must create an object of Math whose number attribute is your computed results and return that for your code to work.
When you execute return self.number + add_num, you return an integer, not an instance of your Math class. To solve this, you can change your add method to
return Math(self.number + add_num).

Python Self Replicating Class

I am messing about with having a class recreate itself. I am trying to get an understanding of metaclass attribute but I am still not 100% clear.
The Goal:
A Class that creates itself for some iteration and then holds its first degree of children it created (In the example below that is one object in self.children).
class MyClass(object):
def __init__(self, num):
self.name = num
self.children = []
if num !=0:
cls = self.__new__(self.__class__ )
cls = self.__init__(num-1)
self.children.append(cls)
#Uncomment for Error
#print cls.name
if __name__ == "__main__":
c = MyClass(3)
This is what I am trying but trying to print self.name of the new object returns a kind AttributeError that "name" does not exist. I think its because I am not passing a dict of the attributes but I am looking for some clarifications of best practice and maybe a solution.
If I was not clear on something please let me know so I can better explain!
There's no need to call the __new__() or __init__() methods yourself; the constructor will handle that part automagically.
class MyClass(object):
def __init__(self, num):
self.name = num
self.children = []
if num !=0:
cls = self.__class__(num-1)
self.children.append(cls)
print cls.name
How about:
class MyClass(object):
def __init__(self, num):
self.name = num
self.children = []
if num != 0:
self.children.append(self.__class__(num - 1))
if __name__=="__main__":
c = MyClass(3)

How to restrict object creation

Consider following example
class Key:
def __init__(self, s):
self.s = s
d = {}
for x in range(1, 10000):
t = Key(x)
d[t] = x
This will create 10000 keys. Is it possible to control the object creation of class key, for example we cannot create more than 5 objects of key class. The loop should not be changed in any ways.
You can control how, or how many objects are created by giving your class a __new__ method:
class Key(object):
_count = 0
def __new__(cls, s):
if cls._count == 5:
raise TypeError('Too many keys created')
cls._count += 1
return super(Key, cls).__new__(cls, s)
def __init__(self,s):
self.s = s
Key.__new__() is called to create a new instance; here I keep a count of how many are created, and if there are too many, an exception is raised. You could also keep a pool of instances in a dictionary, or control creating of new instance in other ways.
Note that this only works for new-style classes, inheriting from object.
You can also use a metaclass approach
import weakref
import random
class FiveElementType(type):
def __init__(self, name, bases, d):
super(FiveElementType, self).__init__(name, bases, d)
self.__cache = weakref.WeakValueDictionary()
def __call__(self, *args):
if len(self.__cache) == 5:
return random.choice(self.__cache.values())
else:
obj = super(FiveElementType, self).__call__(*args)
self.__cache[len(self.__cache)] = obj
return obj
class Key(object):
__metaclass__ = FiveElementType
def __init__(self, s):
self.s = s
You can choose a random element or select it on the base of stored index. In this approach your loop don't fail with an exception that can be right or not, depending on your intention.

A class with no contructor (Python)

Given that I need to operate a machine, I need a
VendingMachine class:
Property is a stock(list) that stores Food items.
Methods:
Constructor takes in no arguments.
get_stock_names(): returns a list of strings that represents the names of
all food items in the stock.
load(food): adds the Food object to stock
and others,
#predefined
class Food(object):
def __init__(self, name, nutrition, good_until):
self.name = name
self.nutrition = nutrition
self.good_until = good_until
self.age = 0
def get_name(self):
return str(self.name)
def get_age(self):
return self.age
def get_nutrition(self):
if self.age <= self.good_until:
return self.nutrition
else:
return 0
def ripen(self, days):
self.age = self.age + days
return self.age
def is_spoiled(self):
return self.good_until < self.age
#my code below
class VendingMachine:
def __init__(self):
Property = Food.get_name #no clue how to make a Property
self.load = Food.load #same here
def get_stock_names(self, Property):
lst = []
for i in Food:
i = str(i)
lst.append(i)
return lst
def has_stock(self, name):
return name in Property
def load(self, food):
Property.append(food)
return Property
def sell(self, name):
if name in Property:
Property.remove(name)
return name
else:
return None
What I get is
AttributeError: 'VendingMachine' object has no attribute 'load' (a variable)
I'm pretty sure you've misunderstood the line of your instructions telling you about the stock property. I suspect it is just telling you to make an instance variable named self.stock which holds a list of Food instances. Since the constructor takes no arguments, it presumably starts empty. Using the term "property" seems like a red herring, since property has a specific meaning in Python (a wrapper around a method to make it look like an attribute), which doesn't make much sense in this situation.
Anyway, here's what I think you want your constructor to look like:
def VendingMachine(object):
def __init__(self):
self.stock = [] # initially empty
Your later methods can inspect or manipulate self.stock as necessary.

Categories