What does self.function in __init__ do to a function? - python

I have recently tried to get into OOP to take a step into more advanced python. I wanted to do a list of functions in a class. I started by not using self.functionName = functionName, this led to an error where the functions could not be identified in the list. So I assumed that what you write in the __init__ function works as global function in the class, so I added self to the first two functions so that they could be used in the other function, and it worked fine. However when I added self to the last functions I did not get the same answer, why is that?
This is the code that I wrote:
>>> class number: #works fine, no self.ans
def __init__(self):
self.numOne = numOne
self.numTwo = numTwo
def numOne(self):
print("one")
def numTwo(self):
print("two")
def ans(self):
bruh = [numOne, numTwo]
for i in bruh:
i()
>>> a = number()
>>> a.ans()
one
two
>>> class number: #now when I write self.ans
def __init__(self):
self.numOne = numOne
self.numTwo = numTwo
self.ans = ans
def numOne(self):
print("one")
def numTwo(self):
print("two")
def ans(self):
bruh = [numOne, numTwo]
for i in bruh:
i()
>>> a = number()
>>> a.ans()
<generator object ans.<locals>.<genexpr> at 0x0000021476FDBF90> #this is the result
>>>

You don't need to assign the methods to the instance in the constructor. That's part of how classes work already.
This works correctly:
class Number:
def num_one(self):
print("one")
def num_two(self):
print("two")
def ans(self):
bruh = [self.num_one, self.num_two]
for i in bruh:
i()
n = Number()
n.ans()
Result:
one
two
Of course, you can still have an __init__ if you need to set some initial values, but a class doesn't require a custom constructor. Just by declaring it as a class, it will have a constructor that you can override as needed.
By the way, you would do well to name your classes with names starting with a capital letter. Naming the methods with camel-case is more of a taste-thing, but I feel the underscore is more pythonic - the capital is definitely something to use however, to avoid people confusing objects and classes.

Related

How can I use a function declared before a class, inside that class in in python 3?

I have this really simple scenario where I want to use one function in multiple classes. So I declare it before the class and then I try to use.
def __ext_function(x):
print(f'Test{x}')
class MyClass():
some_value: int
def __init__(self, some_value):
self.some_value = some_value
__ext_function(1)
a = MyClass(some_value=1)
But for some reason it keeps telling me that it does not exit:
NameError: name '_MyClass__ext_function' is not defined
I have seen other questions with solutions like this:
def __ext_function(x):
print(f'Test {x}')
class MyClass():
some_value: int
ext_func = staticmethod(__ext_function)
def __init__(self, some_value):
self.some_value = some_value
self.ext_func(1)
a = MyClass(some_value=1)
But none seems to work.
This is a case where Python's usually pure syntax fails. Symbols that start with two underscores get treated specially in a class. If you change that function name to _ext_function, it will work exactly as you expect.

How to append a global list from inside a function

What is the best way to append and clear the list deriv_position = [] from inside the function test?
I got NameError: name 'deriv_position' is not defined
class TestClass:
deriv_position = []
def test():
if len(deriv_position) > 0:
print("trade is open")
deriv_position.clear()
else:
print("trade is close")
deriv_position.append("1")
test()
In python, you refer to class variables using the self keyword. So inside the function, you can pass in self and then use it...
class TestClass:
def __init__(self):
self.deriv_position = []
def test(self):
if len(self.deriv_position) > 0:
print("trade is open")
self.deriv_position.clear()
else:
print("trade is close")
self.deriv_position.append("1")
TestClass().test()
You may find it worthwhile to read up on how classes work in Python:
https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes
Alternatively, if you are not using the class as a class (in your example, you are not), then there is no need for it. Just declare a global variable at the top of the file, and the test function just a function in the file.

Reuse a class's method in the main.py

I've searched a lot about how to reuse a method from a class in the main.py file. i got some similar and basic solutions but in my case is a bit different.
/lib/module.py
class Myclass:
def __init__(self, x):
self.thisX = x
def check(self):
if self.thisX == 2:
print("this is fine. going to print it")
self.printing()
# this method will use in this class and must use from the main.py
# the parameter "z" is gonna use only when the method will call from main.py
def printing(self, z):
if z == 1 :
print("we got ", z)
else:
print(self.x)
/main.py
from lib.module import Myclass
# this is how i use the check() method once in my main.py
Myclass(2).check()
# the Myclass() gets "2" only once at the beginning of the program...
# i don't wanna pass "2" to the Myclass() everytime that i wanna use the printing() method...
c = Myclass()
c.printing(1)
error
TypeError: __init__() missing 1 required positional argument: 'x'
testing:
if i don't use the def init(), everything will be fine. but the problem is i need to keep it
This line in main.py:
c = Myclass()
Calls this function:
class Myclass:
def __init__(self, x):
self.thisX = x
Every time you create an instance of Myclass it will call the __init__() function. You declared it to take 2 arguments: self and x. self is always passed implicitly because it's a class, but you need to give it an argument 'x'.
So you can change main.py to this for example:
c = Myclass(2) # here x = 2
c.printing(1)
Please read this for more information
Also, in general, class names are written in CapWords style so it's a good idea to call your class MyClass instead of Myclass
Edit:
Since you don't want to pass x to __init__() and you want to set x from main.py you can try something like this:
class Myclass:
x = 0
def check(self):
if self.x == 2:
print("x is 2")
from main.py you can do:
Myclass.x = 2; #this only needs to be done once
Myclass().check()
Output:
x is 2
I think #richflow 's answer hit the point. If some variable is to be shared by all instances of a class, it's logical to assign its value using Myclass.x = new_number. Then all instances of this class will know the change.
If you really want to optionally change x in the __init__ method of an instance, you can still do it. Combining with #richflow's codes, it can look like the following.
class Myclass:
x = 0
def __init__(self, x=None):
if x is not None:
Myclass.x = x
# other codes for initializiing the instance
def check(self):
if Myclass.x == 2:
print("this is fine. going to print it")
def printing(self, z=0):
if z == 1 :
print("we got ", z)
else:
print(Myclass.x)
I tried not to change too much from your codes. Your main.py should work correctly with this class definition. However, the design looks a bit weird to me. Probably that's because I didn't understand clearly what the check and printing methods are really doing, and what the argument z is really doing in printing methods. If you provides more insights, probably people can help you with a better design.

Yahtzee game, __str__ not working

I realize I've been pretty much spamming this forum lately, I'm just trying to break my problems down since I'm supposed to create a yahtzee game for assignment. My code is currently looking like this:
class Player:
def __init__(self,name):
self.name=name
self.lista={"ones":0,"twos":0,"threes":0, "fours":0,"fives":0,"sixs":0,"abovesum":0,"bonus":0,"onepair":0,"twopair":0,"threepair":0,"fourpair":0,"smalladder":0,"bigladder":0,"house":0,"chance":0,"yatzy":0,"totalsum":0}
self.spelarlista=[]
def __str__(self):
return self.name
def welcome(self):
print("Welcome to the yahtzee game!")
players = int(input("How many players: "))
rounds=0
while not players==rounds:
player=input("What is your name?: ")
rounds=rounds+1
self.spelarlista.append(Player(player))
print(self.spelarlista)
def main():
play=Player("Joakim")
play.welcome()
for key in ["names","ones","twos","threes","fours","fives","sixs","abovesum","bonus","onepair","twopair","threepair","fourpair","smalladder","bigladder","house","chance","yatzy","totalsum"]:
print("%-20s"%key)
main()
My goal is that its gonna look something like this: https://gyazo.com/26f997ed05c92898d93adaf0af57d024
If you look at my method "welcome", I do want to print my self.spelarlista, just to see how its gonna look, but all I get is "Player object at 0x7fac824....", I realize something is wrong with my str, how should I change it?
If you are getting Player object at 0x7fac824 or anything similar, it seems that you are calling the repr on the object (indirectly), which in turn calls the object's __repr__ method.
class Player:
# ...
def __repr__(self):
return self.name
# ...
Since there is no __str__ method defined, __str__ will also default to calling __repr__.
__repr__ returns a string representation of the object (usually one that can be converted back to the object, but that's just a convention) which is what you need.
When you print a list of objects python doesn't call the objects __str__ method but the container list. If you want to print them all you can call the __str__ method by applying the built-in function str() on them using map() or a list comprehension and join them with str.join() method.
print(' '.join(map(str, self.spelarlista)))
Or as another alternative approach you can define a __repr__ attribute for your objects, which returns the official string representation of an object:
>>> class A:
... def __init__(self):
... pass
... def __repr__(self):
... return 'a'
...
>>> l = [A()]
>>>
>>> print l
[a]

Python - Help on genetic algorithm error

I've been trying to create a genetic algorithm in python but i either get:
<bound method Environment.bestsol of <__main__.Environment instance
at 0x10a5d4ab8>>
or it doesn't print. I've tried to rearrange the functions, and call the function directly, but it still does not output anything. I seem to be having trouble with something relating to the function bestsol().
import random
import sys
from operator import attrgetter
input = 1
target = 5.5
class Individual:
def __init__(self, constant):
self.fitness = getfitness()
self.constant = constant
def getconstant():
return self.constant
def getresult():
return self.constant * input
def getfitness():
return 10 - abs(target - self.getresult())
def mutate():
if(random.random() > .05):
self.constant + random.random()
def offspring(partner):
return Individual(((self.getconstant() + partner.getconstant())/2))
class Generation(list):
def __init__(self, gensize, fitsize, startinglist=[]):
self.extend(startinglist)
self.bredoff = []
self.gensize = gensize
self.fitsize = fitsize
self.make()
def make():
self = [Individual(random.randint(-10,10)) for x in xrange((self.gensize-len(self)))]
def getfittest():
return heapq.nlargest(self.fitsize,self,key=attrgetter('fitness'))
def getbredoffspring():
for i in self.getfittest():
bredoff.append(i.offspring(self.getfittest[random.randint(0,len(self.getfittest()))]))
return bredoff
class Environment():
def __init__(self, maxgens):
self.l = []
self.b = []
self.maxgens = maxgens
def create():
l = Generation(100,20)
for i in maxgens:
b = l.getbredoffspring()
l = Generation(100,20,b)
def bestsol():
print("e")
print max(l,key=attrgetter('fitness')).fitness()
def main():
sol = Environment(2)
print sol.bestsol
if __name__ == '__main__':
main()
With me being new to python i can't understand even after searching the internet as best i could. Any help will be appreciated.
bestsol is a class method, so when you call it you should use brackets: sol.bestsol() (otherwise, you're print the method object: <bound method Environment.bestsol ...).
Second, when you define a class-method you should declare self as an argument:
def bestsol(self): # <-- here
print("e")
print max(l,key=attrgetter('fitness')).fitness()
Third, when you declare a class that doesn't extend any other class - you should either declare that it inherits from object (old way):
class Environment(object):
or, no brackets at all (new way)
class Environment:
Forth, when you create a class member, say l (you really should use better names btw), whenever you want to use it you should use the self annotation: self.l. If you'll use l it will create a local variable inside the method - and that's probably not what you intended.
There are other problems with the code but I'll let you struggle with it a bit so you can learn :)

Categories