I'm writting a Fraction class and I am trying to use gcd(a,b) in the initialization of a Fraction object. However, when I was trying to do this it would not work WITHOUT the Fraction part of Fraction.gcd(a,b). I used #staticmethod here, but it does absolutely nothing, i.e. my code works the same without it.
Is there anyway I can call gcd without putting Fraction. in front of it? In Java I would normally create a static method and then just call it. I could very easily put the GCD code inside of the init, but I am trying to learn here!
I am missing a lot here. Can anyone explain: static methods, helper methods in a class and pretty much how I can use various methods inside of a class?
class Fraction(object):
def __init__(self, a, b):
if Fraction.gcd(a, b) > 1:
d = Fraction.gcd(a, b)
self.num = a/d
self.denom = b/d
else:
self.num = a
self.denom = b
#staticmethod
def gcd(a,b):
if a > b: a,b = b,a
while True:
if b % a == 0: return a
a, b = b%a, a
def __repr__(self):
return str(self.num) + "/" + str(self.denom)
Don't forget, in Python not everything needs to be in a class. There's nothing about gcd that makes it better-suited to being a class method than a standalone function: so take it out of the class. Now you can just call gcd(a, b).
Think of methods in a class just like any other class attribute -- reference them on self:
def __init__(self, a, b):
if( self.gcd(a,b) > 1):
d = self.gcd(a,b)
It doesn't matter whether it's an instance method, class method, or static method.
While you certainly can use a staticmethod if you want to keep the code associated with the class, it's usual in Python to use a module-level function, in which case you can call it as gcd:
def gcd(a,b):
if a > b: a,b = b,a
while True:
if b % a == 0: return a
a, b = b%a, a
class Fraction(object):
def __init__(self, a, b):
if( gcd(a,b) > 1):
d = gcd(a,b)
If you have a big method within your class that requires many calls to a static method you can define a local function object and assign the method to it so you can call this function instead.
For Static Method gdc:
class Fraction(object):
def __init__(self, a, b):
gcd = Fraction.gcd
if( gcd(a,b) > 1):
d = gcd(a,b)
self.num = a/d
self.denom = b/d
else:
self.num = a
self.denom = b
#staticmethod
def gcd(a,b):
if a > b: a,b = b,a
while True:
if b % a == 0: return a
a, b = b%a, a
def __repr__(self):
return str(self.num) + "/" + str(self.denom)
For Instance Method gdc:
class Fraction(object):
def __init__(self, a, b):
gcd = self.gcd
if( gcd(a,b) > 1):
d = gcd(a,b)
self.num = a/d
self.denom = b/d
else:
self.num = a
self.denom = b
def gcd(self,a,b):
if a > b: a,b = b,a
while True:
if b % a == 0: return a
a, b = b%a, a
def __repr__(self):
return str(self.num) + "/" + str(self.denom)
So
gcd = Fraction.gcd
and
gcd = self.gcd
will allow you to call (without Fraction at the beginning as per your request :))
gcd(a,b)
Also, if you want some basic examples of python classes and instance/static methods
have a look at some of my blog posts, specially the one called "Factorial and Fibonacci in Jython":
http://carlosqt.blogspot.com/search/label/Jython
I think you are referring to Java's "import static" feature.
Just to clarify: as Java enforces object orientation, it cannot have "modules" like other languages. So using import static Math.*; for example will make all static methods on Math available to be called without the class name.
In Python you can just add this function outside a class and call it.
That's how static methods work. You call them via Classname.methodname() (or via instance.methodname(), but self won't be available inside the method).
What you want is a regular function on the module level. Define it outside the class and do not decorate it.
Related
I’m studying python through the paid online course and i got an error by typing following codes while studying module and pakages.
class Fibonacci:
def __init__(self, title="fibonacci"):
self.title = title
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a + b
print()
def fib2(n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a + b
return result
and the def shows an error like "def Method should have "self" as first argument".
do you know why am i having an error? i think my code should be okay, and when i try to run it though my friends laptop(window) it works well btw, I’m using mac os.
sorry I’m just new to python .. :) click to see the error here
----- edited -----------------
thanks for the comments! and i have edited like the pictureedited code and it has no error! :)
but when i try to call the function, has an error like TypeError: fib() missing 1 required positional argument: 'n'
from pkg.fibonacci import Fibonacci
Fibonacci.fib(100)
see the error message
error message2
This is because all the functions within a class must have an argument named self if you want to bind the function to the class.
self represents the instance of the class. By using the self keyword we can access the attributes and methods of the class in python. It binds the attributes with the given arguments
Try This
class Fibonacci:
def __init__(self, title="fibonacci"):
self.title = title
def fib(self,n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a + b
print()
def fib2(self,n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a + b
return result
Refer Self in Python Class
Edit:
Answering your other question
An object should be used while calling the class functions. So you have to define an object before you call the function.
Like this
from pkg.fibonacci import Fibonacci
f = Fibonacci()
f.fib(100)
Not sure if the fib / fib2 is the class method.
if they are, you may add self in the object parameter, as
def fib(self, n)
Then you may call the method like:
f = Fibonacci()
f.fib(5)
The self parameter is referring to the class object, so that you may use self attributes in the class method, in you case, you may have
def fib(self, n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a + b
print()
print(self.title)
That's more likely a warning rather than an error.
And the warning is saying that you're declaring a method as a part of the class but it's not really bound to any object(missing self). If you're doing that on purpose, that means you ought to use static methods.
So you could either go ahead and add self to both those functions like has been suggested in the other answer, or you could use static methods
class Fibonacci:
def __init__(self, title="fibonacci"):
self.title = title
#staticmethod
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a + b
print()
#staticmethod
def fib2(n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a + b
return result
And the way you'd call it would be Fibonacci.fib(your_num_here)
So I have a class with a couple of (normal) methods. Depending on a value I want to call different methods. This behavior of choosing methods is static (same for all instantiation of the classes. How would you recommend doing this?
Will the answer change on best way to achieve this if the state of an instantiation is constant and never changes after initialization?
Example:
PLUS = 0
MINUS = 1
OPERATIONS = [PLUS, MINUS]
class Generator(object):
operations = {
PLUS: self.plus, # Not possible
MINUS: self.minus,
}
def __init__(self, state):
self._state = state
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def generate(self):
a, b = give_me_numbers()
for op in OPERATIONS:
print self.operations[op](a, b)
PLUS = 0
MINUS = 1
OPERATIONS = [PLUS, MINUS]
class Generator:
operations = {}
def __init__(self, state):
self._state = state
#classmethod
def init_operations(cls):
cls.operations = {
PLUS: cls.plus,
MINUS: cls.minus
}
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def generate(self):
a, b = 5, 10
for op in self.operations:
print( self.operations[op](self, a, b) )
gen = Generator(1)
gen.init_operations()
gen.generate()
In order for operations to store functions of a class definition it can't be done at the top of a class like you have done. This is because the parser won't find the functions you're referring to because it hasn't parsed them yet. So instead I've added a 'static' init_operations().
Note these operations are stored as unbound methods (since it's called from within a static); therefore when calling these functions it is necessary to include the self variable as the 1st argument.
One option is to turn operations into a method:
def operations(self, op):
dictMethods = {
"PLUS" : self.plus
"MINUS" : self.minus
}
return dictMethods[op]
Then call it like:
self.operations(op)(a, b)
Here's a slight modification to Richard's code that automatically calls the init_operations method the first time you instantiate a Generator.
class Generator:
def __init__(self, state):
self._state = state
if not hasattr(self, 'operations'):
self.init_operations()
#classmethod
def init_operations(cls):
cls.operations = {
PLUS: cls.plus,
MINUS: cls.minus,
}
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def generate(self):
a, b = give_me_numbers()
for op in self.operations:
print self.operations[op](self, a, b)
Here's an alternative that makes operations a plain instance attribute. This wastes a little bit of space, but it means you don't need to explicitly pass self when you call an operation.
class Generator(object):
def __init__(self, state=False):
self._state = state
self.operations = {
PLUS: self.plus,
MINUS: self.minus
}
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def generate(self):
a, b = give_me_numbers()
for op in OPERATIONS:
print self.operations[op](a, b)
And finally, this variation uses the method names to identify the operations instead of integers.
#!/usr/bin/env python
from random import seed, randint
def give_me_numbers():
a, b = randint(1, 99), randint(1, 99)
print 'a=%d, b=%d' % (a, b)
return a, b
OPERATIONS = ('plus', 'minus')
class Generator(object):
def __init__(self, state=False):
self._state = state
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def operations(self, op):
return getattr(self, op)
def generate(self):
a, b = give_me_numbers()
for op in OPERATIONS:
#print getattr(self, op)(a, b)
print self.operations(op)(a, b)
seed(42)
g1 = Generator(False)
g1.generate()
g2 = Generator(True)
g2.generate()
output
a=64, b=3
67
-61
a=28, b=23
51
5
You don't really need the operations method here - I just left it in to stay (relatively) consistent with the OP code. Instead, you can just call getattr(self, op)(a, b) directly. OTOH, it is cleaner to supply the operations method if you want to call it from outside the class.
What you want to do actually works (there is no need for a more complicated solution), but you have to (1) write the dictionary definition of operations properly (with : instead of =) and (2) put its definition when it can be understood (after the methods that it refers to are defined):
PLUS = 0
MINUS = 1
OPERATIONS = [PLUS, MINUS]
class Generator(object):
def __init__(self, state):
self._state = state
def plus(self, a, b):
# Depends on state
return a + b
def minus(self, a, b):
return a - b if self._state else b - a
def generate(self):
a, b = give_me_numbers()
for op in OPERATIONS:
print operations[op](a, b)
operations = { # plus and minus are defined, at this point
PLUS: plus,
MINUS: minus
}
Side notes:
Note the Generator(object) syntax (not Generator())—or simply Generator, in Python 3.
You might want check out the enum module, which handles the constants PLUS, MINUS and OPERATIONS that you define in a clean and convenient way.
PS: As PM 2Ring noted, using the values from operations can be done through self.operations[op](self, a, b). I would personally do Generator.operations[op](self, a, b), since operations is not specific to any instance and is instead a dictionary associated with the Generator class.
What is a nice way to make different variables refer to the same value, while still allowing direct operations like e.g. * on the value?
Example of desired code is being able to do something like:
a = <Reference to integer 2>
b = a
print(a * b) # Should show 4
<a update (not with assign using =) with reference to integer 3>
print(a * b) # Should show 9
A less desired solution is to use a container for the value, like namespace, list, dict, etc., but this requires reference to the attribute like .value below, so is less desired:
import types
a = types.SimpleNamespace(value = 2)
b = a
print(a.value * b.value) # Should show 4
a.value = 3
print(a.value * b.value) # Should show 9
What is a nice way to encapsulate the value, so direct operations is still possible?
You could create a class which overrides the multiply operation.
class Reference:
def __init__(self, value):
self.value = value
def __mul__(self, other):
return Reference(self.value * other.value)
This will allow you to multiply references by one another directly. For example, Reference(3) * Reference(4) produces Reference(12).
You'll probably want to override __rmul__ and all the other numerical operations as well. The abstract classes in numbers may prove useful to ensure you don't forget any.
Your desired behaviour can be simulated with a class, although a bit clunky and inelegant:
class reference:
def __init__(self, num): self.num = num
def get(self): return self.num
def set(self, num): self.num = num
def __mul__(self, other): return self.num * other
def __div__(self, other): return self.num / other
def __add__(self, other): return self.num + other
def __sub__(self, other): return self.num - other
With these operators overloaded, the following:
a = reference(5)
b = a
print a.get()
print a * 4
prints
5
20
I realise this is quite cumbersome if you want to reference different types, as you would have to overload the operators you need for every type, but AFAIK it's the closest you'll get to simulating pointers.
Alternatively, you can include only get, set and __init__ in your reference class, then add the overloading functions you need later:
class reference:
def __init__(self, num): self.num = num
def get(self): return self.num
def set(self, num): self.num = num
a = reference(5)
reference.__mul__ = lambda self, num: self.num * num
print a * 4
The above prints 20
class Manager:
def __init__(self,data):
self.__dict__["data"] = data
def __getattr__(self,attr):
return getattr(self.data,attr)
def __setattr__(self,attr,val):
return setattr(self.data,attr,val)
def set(self,val):
self.__dict__["data"] = val
master = Manager(55)
print print master+5
print slave = master
print slave.set(88)
print slave + 10
print master+2
...
master_s = Manager("Test")
print master_s + " String"
...
master_c = Manager(MyCustomClass())
master_c.do_my_method()
maybe?
You can use a list around the object:
>>> a = [2]
>>> b = a
>>> print(a[0]*b[0])
4
>>> a[0]+=1
>>> print(a[0]*b[0])
9
To use the container classes, but still allow direct operations, you can overload the operators you wish to use for that type. As an example, define class SharedInt and write an overload for the * operator that takes two SharedInt's as arguments.
__mul__(self, other):
return self.value * other.value
I want to create a class in python, which should work like this:
Data assigned, maybe bound to a variable (eg a = exampleclass(data) or just exampleclass(data))
Upon being inserted data, it should automatically determine some properties of the data, and if some certain properties are fullfilled, it will automatically...
... change class to another class
The part 3 is the part that i have problem with. How do i really change the class inside of the class? for example:
If I have two classes, one is Small_Numbers, and the other is Big_numbers; now I want any small_number smaller than 1000 to be transferred into a Big_number and vice versa, testcode:
a = Small_number(50)
type(a) # should return Small_number.
b = Small_number(234234)
type(b) # should return Big_number.
c = Big_number(2)
type(c) # should return Small_number.
Is this possible to do?
Why not using a factory method? This one will decide which class to instanciate depending on the passed data. Using your example:
def create_number(number):
if number < 1000:
return SmallNumber(number)
return BigNumber(number)
Using a factory method is the usual way to solve this, especially since instantiating a class is indistinguishable from calling a function in Python.
However, if you really want, you can assign to self.__class__:
THRESHOLD = 1000
class Small(object):
def __init__(self, n):
if n < THRESHOLD:
self.n = n
else:
self.__class__ = Big
self.__init__(n)
class Big(object):
def __init__(self, n):
if n < THRESHOLD:
self.__class__ = Small
self.__init__(n)
else:
self.n = n
This works as expected:
>>> a = Small(100)
>>> type(a)
<class 'Small'>
>>> b = Small(1234)
>>> type(b)
<class 'Big'>
>>> c = Big(2)
>>> type(c)
<class 'Small'>
If assigning to self.__class__ seems too strange, then you can override __new__ instead. This method is called before __init__ is called and it can be used to pick the class to instantiate:
THRESHOLD = 1000
class Switcher(object):
def __new__(cls, n):
if n < THRESHOLD:
new_cls = Small
else:
new_cls = Big
instance = super(Switcher, new_cls).__new__(new_cls, n)
if new_cls != cls:
instance.__init__(n)
return instance
class Small(Switcher):
def __init__(self, n):
self.n = n
class Big(Switcher):
def __init__(self, n):
self.n = n
Don't. Use a factory function instead.
def create_number(source):
if source < 1000:
return Small_number(source)
else:
return Big_number(source)
a = create_number(50)
b = create_number(234234)
c = create_number(2)
This question already has answers here:
How to access a function inside a function?
(6 answers)
Closed 6 years ago.
Python noob here.
How do I get hold of the 'inner' function within the 'fib' function?
from time import sleep
class Fibonacci(object):
def __init__(self, a, b, limit=50):
self.a = a
self.b = b
self.limit = limit
def fib(self):
while self.a < self.limit:
c = self.a + self.b
sleep(1)
print self.a,
self.b = self.a
self.a = c
def inner(self):
print 'Damn it! Just print already!'
j = Fibonacci(0,1,2)
j.fib()
## This doesn't work. Gives an "AttibuteError: 'function' object has no attribute 'inner'"
j.fib.inner()
You cannot, not unless fib returns inner somehow. inner is essentially a local variable inside the scope of fib and you can't access a function's locals from outside of it. (That wouldn't even make sense, since the locals don't exist except when the function is running. Think about it -- would it make sense to access fib's c variable from outside of the function?)
Do not use the following.
[...]
>>> j = Fibonacci(0,1,2)
>>> j.fib()
0 1 1
>>> # dark magic begins!
>>> import new
>>> new.function(j.fib.im_func.func_code.co_consts[2],{})(None)
Damn it! Just print already!
You can tell simply by looking at it that it's not really Python, and for that matter it isn't really calling the "inner" function itself, it's simply creating a new function like it. I also didn't bother setting the globals 'correctly', because this is a terrible thing to do in the first place..
[I should mention that the point of the above is to note that the idea that you can't access internals from outside isn't strictly true, though it's almost never a good idea. Exceptions include interpreter-level code inspections, etc.]
Unclean! Unclean!
from time import sleep
class Fibonacci(object):
def __init__(self, a, b, limit=50):
self.a = a
self.b = b
self.limit = limit
def fib(self):
while self.a < self.limit:
c = self.a + self.b
sleep(1)
print self.a,
self.b = self.a
self.a = c
def inner(self):
print 'Damn it! Just print already!'
Fibonacci.fib.inner = inner
fib.inner = None
This code snippet will allow you to use inner.
The below seems to achieve what you want
from types import CodeType, FunctionType
def find_nested_func(parent, child_name):
""" Return the function named <child_name> that is defined inside
a <parent> function
Returns None if nonexistent
"""
consts = parent.func_code.co_consts
for item in consts:
if isinstance(item, CodeType) and item.co_name==child_name:
return FunctionType(item, globals())
As stated by some of the other readers, it's a problem of scope. FWIW, this works by returning the inner function:
from time import sleep
class Fibonacci(object):
def __init__(self, a, b, limit=50):
self.a = a
self.b = b
self.limit = limit
def fib(self):
while self.a < self.limit:
c = self.a + self.b
sleep(1)
print self.a,
self.b = self.a
self.a = c
def inner():
print 'Damn it! Just print already!'
return inner
j = Fibonacci(0,1,2)
j.fib()()
For reference, here's a good intro to python's scoping:
Short Description of the Scoping Rules?