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.
Related
I was trying to call the objects of a method in one of my classes within antoher method of the same class. Below you can find a small example of how I tried to do it:
class example_class():
def some_method(self):
#... calculate something ...
a = 1
b = 2
def second_method(self):
call = self.some_method()
c = call.a + call.b
If I do this, I get the error: "'NoneType' object has no attribute 'a'".
I am sure this is a fearly basic problem, but I am using classes, objects and methods for the first time and would really appreciate the help!
Thank you in advance and stay safe!
class example_class():
def some_method(self):
#... calculate something ...
self.a = 1
self.b = 2
def second_method(self):
# call = self.some_method()
c = self.a + self.b
This should work
class example_class:
def some_method(self):
self.a = 1
self.b = 2
def second_method(self):
self.some_method()
print(self.a + self.b)
You can't access a method's local variables from another method, you should store them as attributes.
I am working with several classes, with each having it's own attributes.
Trying to avoid to pass a lot of variables when calling sub_functions, I would rather call classe's attributes.
As an example, let's concider 2 classes such as :
class Class_A(object):
def __init__(self, element_b):
self.value_specific_to_a = 1
self.element_b = element_b
def element_a_can_do(self):
print(self.element_b.value_specific_to_b)
class Class_B(object):
def __init__(self):
self.element_a = None
self.value_specific_to_b = 2
def add_a(self, element_a):
self.element_a = element_a
def element_b_can_do(self):
print(self.element_a.value_specific_to_a)
item_b = Class_B()
item_a = Class_A(item_b)
item_b.add_a(item_a)
I think that it is pointer's addresses of those classes that are save to each other, but I wonder if it can cause any issue/leak in my code.
I am looking for best practices on setting one instance attribute that references another instance attribute after the class has been instantiated.
For example:
class Foo:
def __init__(self):
self.a = 1
self.b = self.a + 1
>>> obj_foo = Foo()
>>> obj_foo.a
1
>>> obj_foo.b
2
>>> obj_foo.a = 5
>>> obj_foo.a
5
>>> obj_foo.b
2 # I want this to be 6
Is this bad practice for one instance attribute to reference another?
I can see how implementing a method to check for and update dependent instance attributes, but this seems like a lot of overhead/hacky. Any assistance is greatly appreciated!
It seems like you don't actually want to store the value of b at all, but instead want to generate it based on the value of a dynamically. Luckily, there's a property class/decorator that you can use just for this purpose:
class Foo:
def __init__(self, a=1):
self.a = a
#property
def b(self):
return self.a + 1
This will create a read-only property b that will behave just like a normal attribute when you access it as foo.b, but will a because it is a descriptor. It will re-compute the value based on whatever foo.a is set to.
Your fears about calling a method to do the computation every time are not entirely unjustified. Using the . operator already performs some fairly expensive lookups, so your toy case is fine as shown above. But you will often run into cases that require something more than just adding 1 to the argument. In that case, you'll want to use something like caching to speed things up. For example, you could make a into a settable property. Whenever the value of a is updated, you can "invalidate" b somehow, like setting a flag, or just assigning None to the cached value. Now, your expensive computation only runs when necessary:
class Foo:
def __init__(self, a=1):
self._a = a
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
self._b = None
#property
def b(self):
if self._b is None:
# Placeholder for expensive computation here
self._b = self._a + 1
return self._b
In this example, setting self.a = a in __init__ will trigger the setter for the property foo.a, ensuring that the attribute foo._b always exists.
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
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?