I'm quite new using Python and can't find the answer to this.
Let's souppose I have a code like:
class numbers():
def __init__(self,a,b):
self._a = a
self._b = b
def add(self):
self._suma = self._a + self._b
After that, I create a lot of instances of numbers:
obj1 = numbers(1,2)
obj2 = numbers(7,16)
...
Then, I want to call the add method in all the objects of the class numbers in a simple and clean way.
Notice that if I instantiated numbers class 1000 times I don't want to write 1000 times this
objX.add()
I looked for an answer in the web and I found that, in other lenguages, they put all the names of the objects in a string, and then iterates on it calling the method.
The problem is I donĀ“t know how to do that in python, nor if it's the best way to solve this problem.
Thank you
create a list of objects.
objs = []
add elements to this list
obj1 = numbers(1,2) # say these are your objects
obj2 = numbers(7,16)
...
objs.append(obj1) # add them to the list
call the add method for each element in the list
for obj in objs:
obj.add() # call the add method.
Well you'll need to have some way to find all the numbers objects. For clarity, I'll adjust your code naming conventions slightly so they're more standard (per PEP9).
class Number(object):
def __init__(self, a, b):
self._a = a
self._b = b
def add(self):
self.sum = self._a + self._b
return self.sum # not really sure where we're using it, so here?
a = Number(1, 2)
b = Number(2, 3)
c = Number(3, 4)
Now we have three objects, a, b, and c, that are all Number objects. There's two ways to get a list of them, and one is really bad. We'll go over that one first.
number_objs = [obj for obj in globals() if isinstance(obj, Number)]
for number in number_objs:
number.add()
This queries the all the objects currently in the namespace to see if they're Numbers. The problem with doing it this way is that you lose encapsulation. You probably don't want to rely on your functions finding a number object by calling globals(). Instead, let's give Number an encompassing object!
class NumberList(list):
# this is literally just a list, but we want to add one method:
def make_number(a, b):
number = Number(a, b)
self.append(number)
all_numbers = NumberList()
a = all_numbers.make_number(1, 2)
b = all_numbers.make_number(2, 3)
c = all_numbers.make_number(3, 4)
for number in all_numbers:
number.add()
Alternatively you can give Number a classmethod that works as an alternate constructor, but also adds it to a list. This is probably the cleanest way to handle it.
class Number(object):
def __init__(self, a, b):
self._a = a
self._b = b
def add(self):
self.sum = self._a + self._b
return self.sum
#classmethod
def track(cls, a, b, container):
n = cls(a, b)
container.append(n)
return n
all_numbers = []
a = Number.track(1, 2, all_numbers)
b = Number.track(2, 3, all_numbers)
c = Number.track(3, 4, all_numbers)
for number in all_numbers:
number.add()
You need to append each obj to a list. To automate that, simply create an empty list and write the code inside the init. This will run automatically every time a new object is created
class numbers():
def __init__(self,a,b):
self.a = a
self.b = b
listObjs.append(self)
def Add(self):
return self.a + self.b
listObjs = []
ob1 = numbers(4,5)
ob2 = numbers(4324,5)
ob3 = numbers(1,25)
ob4 = numbers(2,5324)
ob5 = numbers(21,5)
ob6 = numbers(4213,54)
Then simply make a loop and print the obj.Add(). This will run for each obj in the list.
for obj in listObjs:
print(obj.Add())
Output:
9
4329
26
5326
26
4267
Related
I'm relying on id(obj) to distinguish two objects in my project. However, this doesn't work when objects are small integers unfortunately due to python's small value caching. The following two elements will have the same id.
self.a = 0
self.b = 0
# id(self.a) is the same as id(self.b)
Is there a way to make id(self.a) different from id(self.b) but still retain the syntax listed above?
Thanks!
EDIT:
See the following example
class B:
def __init__(self):
self.b = 0
def eat( self ):
self.b = 0
class A:
def __init__(self):
self.b = B()
self.a = 0
def eat1( self ):
self.a = 0
def eat2( self ):
self.b.b = 0
a = A()
a.b.eat()
a.eat2()
Basically a.b.eat() is accessing the same variable as a.eat2() and eat1() is accessing a different variable. However, self.b.b and self.a have the same id which makes it hard to distinguish between them.
class classname():
def func(self,a,b):
self.c = a+b
self.d = a-b
self.e = a*b
return self
cn = classname()
This way i can access cn.c, cn.d and cn.e can i use something else other then self to return it and it will be a structure. I know its possible in matlab where you can define structure in a function. Something what i expect should look like this:
class classname():
def func(self,newself,a,b):
self.c = a+b
self.d = a-b
newself.e = a*b
return self, newself
cn = classname()
I know this is not a valid code but just an idea what i want from code.
I think what you want is this:
class classname:
def __init__(self, a, b):
self.c = a+b
self.d = a-b
self.e = a*b
cn = classname(12, 34) # Just random values for 'a' and 'b'. Use whatever you like!
print(cn.c)
>>> 46
print(cn.d)
>>> -22
print(cn.e)
>>> 408
The __init__ function is automatically called when the object is created. Self will always refer to the object, so adding attributes to it will add it to the object, so you don't need to return anything.
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?