I am following a tutorial from: http://sthurlow.com/python/lesson08/
I do not understand the following:
Any function or variable created on the first level of indentation
(that is, lines of code that start one TAB to the right of where we
put class Shape is automatically put into self. To access these
functions and variables elsewhere inside the class, their name must be
preceded with self and a full-stop (e.g. self.variable_name).
Here is part of the example used:
#An example of a class
class Shape:
def __init__(self,x,y):
self.x = x
self.y = y
description = "This shape has not been described yet"
author = "Nobody has claimed to make this shape yet"
def area(self):
return self.x * self.y
def perimeter(self):
return 2 * self.x + 2 * self.y
def describe(self,text):
self.description = text
I understand how self.x affects __ init __ part of the code, but not for functions because they seem to play by different rules (e.g. i cannot access variables from inside functions)... In other words, i'm trying to figure out what self.x is doing in the functions. if I put only x in the function what does it do? If I put x in __ int __ it only 'lives' in __ int and cannot be called when I make an object . If I put self.x in __int it can be called when I make an object. I am wondering about self.x vs x in functions because I cannot figure out code to test it
I understand how self.x affects __ init __ part of the code, but not for functions because they seem to play by different rules (e.g. i cannot access variables from inside functions)...
No, they really don't play by different rules. __init__ is just a function, defined in a class definition, exactly like area.
They both take self as an explicit parameter, and have to use that self if they want to access or set instance attributes like x, or call instance methods like describe.
The only difference is how they're called:
area is something that you call directly. When you write my_shape.area(), that calls the area function passing my_shape as the value of self.
__init__ is something that Python calls automatically. When you write my_shape = Shape(2, 3), Python constructs a new Shape object, and then calls the __init__ function passing that new object as self (and 2 and 3 as x and y).
In other words, i'm trying to figure out what self.x is doing in the functions. if I put only x in the function what does it do?
Plain old x is a local variable if you have one, a global variable if you don't. So, inside __init__, where there's a parameter named x, it's that x (e.g., it's 2 in the Shape(2, 3) example). Inside area, where there is nothing local named x, it would be a global variable. But you probably don't have a global named x either, so it would raise a NameError.
self.x, on the other hand, is the x attribute of whatever self is. As explained above, self is a newly-created Shape instance inside __init__, and whatever Shape instance you called area on inside area.
If I put x in __ int __ it only 'lives' in __ int and cannot be called when I make an object .
Yes, if you define something named x in __init__, it's a local variable, so it only lives within __init__. That's true for any function—not just __init__, not even just methods defined in a class; that's what local variables mean. Once the function ends, those variables are gone, and nobody can ever access them again. (This isn't quite true if closures are involved, but they aren't here, so ignore that.)
I don't know what you mean by "called", because you don't normally call values that aren't functions/methods/classes, and I don't know what you mean by "when I make an object", because when you make an object is exactly when __init__ gets called.
If I put self.x in __int it can be called when I make an object.
Anything you assign to self.x inside __init__ gets stored as part of that self instance. So, it can be accessed again by anyone who has that instance. For example, inside area, you can access it as self.x. Or, from top-level code, you can access it as my_shape.x.
Again, there's nothing special about __init__ here; you could do the same thing in another method—as the describe method does. You could even do it from outside the object.
For example:
>>> my_shape = Shape(2, 3)
>>> my_shape.x
2
>>> my_shape.area()
6
>>> my_shape.x = 4
>>> my_shape.area()
12
Again, I don't know what you mean by "called" or by "when I make an object".
I am wondering about self.x vs x in functions because I cannot figure out code to test it
Try adding this method:
def play_with_x(self):
x = 10
print(x)
print(self.x)
x = 20
print(x)
print(self.x)
self.x = 30
print(x)
print(self.x)
Then try this:
>>> x = 0
>>> my_shape = Shape(2, 3)
>>> my_shape.play_with_x()
You'll see that it can change x and self.x. They're completely independent of each other, but mostly seem to act the same from within one function. But now:
>>> x
0
>>> my_shape.x
30
That x = 20 didn't do anything to the global variable x. But that self.x = 30 did permanently change self, which is the same object as my_shape, so my_shape.x is now 30.
Related
Let's say I have the following classes:
import math
class LineSegment:
def __init__(
self,
origin,
termination,
):
self.origin = origin
self.termination = termination
self.length = self.calculate_length()
def calculate_length(self):
return math.sqrt(
(self.origin.x - self.termination.x) ** 2
+ (self.origin.y - self.termination.y) ** 2
)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
An object of the LineSegment class is composed of two objects of the Point class. Now, let's say I initialize an object as so:
this_origin = Point(x=0, y=0)
this_termination = Point(x=1, y=1)
this_line_segment = LineSegment(origin=this_origin, termination=this_termination)
Note: The initialization of the line segment automatically calculates its length. This is critical to other parts of the codebase, and cannot be changed. I can see its length like this:
print(this_line_segment.length) # This prints "1.4142135623730951" to the console.
Now, I need to mutate one parameter of this_line_segment's sub-objects:
this_line_segment.origin.x = 1
However, the this_line_segments length attribute does not update based on the new origin's x coordinate:
print(this_line_segment.length) # This still prints "1.4142135623730951" to the console.
What is the pythonic way to implement updating a class's attributes when one of the attributes they are dependent upon changes?
Option 1: Getter and Setter Methods
In other object-oriented programming languages, the behavior you desire, adding additional logic when accessing the value of an instance variable, is typically implemented by "getter" and "setter" methods on all instance variables in the object:
class LineSegment:
def __init__(
self,
origin,
termination,
):
self._origin = origin
self._termination = termination
# getter method for origin
def get_origin(self):
return self._origin
# setter method for origin
def set_origin(self,new_origin):
self._origin = new_origin
# getter method for termination
def get_termination(self):
return self._termination
# setter method for termination
def set_termination(self,new_termination):
self._termination = new_termination
def get_length(self):
return math.sqrt(
(self.get_origin().x - self.get_termination().x) ** 2
+ (self.get_origin().y - self.get_termination().y) ** 2
) #Calls the getters here, rather than the instance vars in case
# getter logic is added in the future
So that the extra length calculation is performed every time you get() the length variable, and instead of this_line_segment.origin.x = 1, you do:
new_origin = this_line_segment.get_origin()
new_origin.x = 1
this_line_segment.set_origin(new_origin)
print(this_line_segment.get_length())
(Note that I use _ in front of variables to denote that they are private and should only be accessed via getters and setters. For example, the variable length should never be set by the user--only through the LineSegment class.)
However, explicit getters and setters are clearly a clunky way to manage variables in Python, where the lenient access protections make accessing them directly more transparent.
Option 2: The #property decorator
A more Pythonic way to add getting and setting logic is the #property decorator, as #progmatico points out in their comment, which calls decorated getter and setter methods when an instance variable is accessed. Since all we need to do is calculate the length whenever it is needed, we can leave the other instance variables public for now:
class LineSegment:
def __init__(
self,
origin,
termination,
):
self.origin = origin
self.termination = termination
# getter method for length
#property
def length(self):
return math.sqrt(
(self.origin.x - self.termination.x) ** 2
+ (self.origin.y - self.termination.y) ** 2
)
And usage:
this_line_segment = LineSegment(origin=Point(x=0,y=0),
termination=Point(x=1,y=1))
print(this_line_segment.length) # Prints 1.4142135623730951
this_line_segment.origin.x = 1
print(this_line_segment.length) # Prints 1.0
Tested in Python 3.7.7.
Note: We must do the length calculation in the length getter and not upon initialization of the LineSegment. We can't do the length calculation in the setter methods for the origin and termination instance variables and thus also in the initialization because the Point object is mutable, and mutating it does not call LineSegment's setter method. Although we could do this in Option 1, it would lead to an antipattern, in which we would have to recalculate every other instance variable in the setter for each instance variable of an object in the cases for which the instance variables depend on one another.
I was writing a small python script to understand a concept and got another confusion. Here's the code -
x = 5
y = 3
class Exp(object):
def __init__(self, x, y):
self.x = x
self.y = y
print("In",x, y, self.x, self.y)
print("Middle",x,y)
print("Out",x,y)
Exp(1,2)
The output is -
Middle 5 3
Out 5 3
In 1 2 1 2
Now, my concept was python interpreter starts reading and executing the code from the first line to last line. It executes the code inside a class only when it is "called", not when it is defined. So, the output should print "Out" first. But here it is printing "Middle" first. This should not happen, as python interpreter when first encounters "Middle" - it is within the definition, and thus should not be executed at that time. It should be executed only after reading the last line of code where the class "Exp" is called.
I searched on Google and StackOverflow for the solution but couldn't find one explaining it for the class.
Kindly help me understand where I'm getting it wrong...
Your doubt is right. I had the same doubt like 6 months back and a friend of mine helped me figure the answer out.
print("Middle",x,y)
The above statement does not belong to any method. It belongs to the class Exp. The __init__() method is executed when an object is created and is internally called by the Python interpreter when an object is instantiated from your end. Since the above statement is not a part of any method, the interpreter executes it before invoking the __init__ method. Since variables x and y are both available in the scope of class Exp, it isn't considered an error and the interpreter executes it.
If you remove the declarations of variables x and y, you will see a NameError like below.
Traceback (most recent call last):
File "trial.py", line 9, in <module>
print("Middle",x,y)
NameError: name 'x' is not defined
And this is because x and y are not even created from the class Exp's perspective.
This odd behaviour happens because your print("Middle",x,y) is not inside a definition of a function, so it gets called before print("Out",x,y).
Your code is equivalent to:
x = 5
y = 3
class Exp(object):
def __init__(self, x, y):
self.x = x
self.y = y
print("In",x, y, self.x, self.y)
print("Middle",x,y)
print("Out",x,y)
Exp(1,2)
Whose output will be:
Middle 5 3
Out 5 3
In 1 2 1 2
One of the possible ways to correct this is to define print("Middle",x,y), say within the constructor.
x = 5
y = 3
class Exp(object):
def __init__(self, x, y):
self.x = x
self.y = y
print("In",x, y, self.x, self.y)
print("Middle",x,y)
print("Out",x,y)
Exp(1,2)
The output you will then get is:
Out 5 3
In 1 2 1 2
Middle 1 2
Class methods are not executed as compiled, they have to be invoked.
With your code above the print(middle) statement is not defined within a class method. Whereas the print(In) statement is defined within the init (also called constructor) method.
When you run the code and the compiler runs through the script, the print(In) statement is not invoked until the init() method is called.
However this print(middle) line is not defined as a method of the Exp class, but is executable as a built-in function, despite the whitespace. Consequently as Python compiles the class Exp the print(middle) statement is invoked. This is the only time the print(middle) statement would be invoked. As it is not in a class method it cannot be accessed later in the program.
If you try the code below, you get the output 'Out' and 'In'. You would only get 'Middle' by calling Exp.test()
x = 5
y = 3
class Exp(object):
def __init__(self, x, y):
self.x = x
self.y = y
print("In",x, y, self.x, self.y)
def test(self):
print("Middle",x,y)
print("Out",x,y)
Exp(1,2)
I have a file that contains the class definitions and functions I need to use in my main file to make the text cleaner. However, I'm having a problem with imported global variables.
There is plenty of information at SO and other resources regarding how to make function variables global within the same code or how to use the global variables from an imported file. However, there is no information on how to access a variable from an imported file if the variable belongs to a function belonging to a class.
I would appreciate any help on how to do it or why it cannot be done. Please skip the lecture on the dangers of using global variables like this as my situation requires such use.
Edit: Sorry for not having an example in the original post. It's my first one. Below is an example of what I'm trying to accomplish.
Let's say I have a file classes.py that contains:
class HelixTools():
def calc_angle(v1, v2):
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
global v1_v2_dot
v1_v2_dot = np.dot(v1,v2)
return v1_v2_dot
Then in my main text file I do:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2)
print(v1_v2_dot)
The result is "v1_v2_dot" not defined. I need v1_v2_dot to use it as the input of another function.
Here's an example of how you can access class attributes (if I understand what it is you want to do correctly). Lets imagine you have a python file called "Test_class.py" that contains the following code:
class Foo(object):
def __init__(self, x, y):
self.x = x
self.y = y
def bar(self):
self.z = self.x + self.y
Now lets imagine you want to import this class into another python file in the same directory, and access attributes of that class. You would do this:
from Test_class import Foo
# Initialize two Foo objects
test1 = Foo(5, 6)
test2 = Foo(2, 3)
# Access the x and y attributes from the first Foo object
print(test1.x) # This will print 5
print(test1.y) # This will print 6
# Access the x and y attributes from the second Foo object
print(test2.x) # This will print 2
print(test2.y) # This will print 3
# Access the z attribute from the first Foo object
test1.bar()
print(test1.z) # This will print 11
# Access the z attribute from the second Foo object
test2.bar()
print(test2.z) # This will print 5
This works because variables defined in the __init__ magic method are initialized as soon as the Foo object is first called, so the attributes defined here can be access immediately after. The bar() method has to be called before you can access the z attribute. I made 2 Foo objects just to show the importance of including "self." in front of your variables, in that each attribute is specific to that particular class instance.
I hope that answers your question, but it would be very helpful if you provided some example code to show exactly what it is you want to do.
You should likely use a class attribute to store this value. Note that the implementation will depend on what your class HelixTools really does.
But for the example, you could use something like this:
import numpy as np
class HelixTools():
def __init__(self):
# Initialize the attribute so you'll never get an error calling it
self.v1_v2_dot = None
def calc_angle(self, v1, v2): # Pass self as first argument to this method
v1_mag = np.linalg.norm(v1)
v2_mag = np.linalg.norm(v2)
# Store the value in the attribute
self.v1_v2_dot = np.dot(v1,v2)
And then:
from classes import HelixTools
ht = HelixTools()
v1 = some vector
v2 = some other vector
ht.calc_angle(v1,v2) # This will not return anything
print(ht.v1_v2_dot) # Access the calculated value
I'm still starting out how to program in Python, and I'm just wondering how to make a variable consistent throughout different functions. For example, a function that I've made modified a variable. Then, I've used that variable again in another function. How can I make the modified variable appear in the 2nd function? When I try it, the 2nd function uses the original value of the variable. How can you make it use the modified value? Do I need to use global variables for this?
Also, is the input() function recommended to be used inside functions? are there any side effects of using it inside them?
The variables need to be shared by a scope that is common to both functions, but this need not necessarily be a global scope. You could, for instance, put them in a class:
class MyClass:
def __init__(self):
self.x = 10
def inc(self):
self.x += 1
def dec(self):
self.x -= 1
mc = MyClass()
print mc.x # 10
mc.inc()
print mc.x # 11
mc.dec()
print mc.x # 10
What scope exactly the variable should exist in depends on what you're trying to do, which isn't clear from your question.
Use global variabale to access variable throughout code.
Demo:
>>> a = 10
>>> def test():
... global a
... a = a + 2
...
>>> print a
10
>>> test()
>>> print a
12
>>>
In class, use class variable which is access to all instance of that class. OR use instance variable which is access to Only respective instance of the class.
You can use return in the function.
x = 3
def change1():
x = 5
return x
x = change1()
def change2():
print(x)
change1()
change2()
You can use the global keyword at the top of the function to let python know that you are trying to modify the variable in global score. Alternatively, you could use OOP and classes to maintain an instance variable throughout class functions.
x = 5
def modify():
global x
x = 3
modify()
def main():
x=2
def cool():
y=4
nonlocal x
print (x)
It is showing an error as --nonlocal x is a invalid syntax--.And if I dont declare it as nonlocal it says undefined x. So, how do i acess a variable which is in some other function ?Now how do i access x variable which is defined at main().
You can't.
You shouldn't. Doing so would just make it hard to read code because code from anywhere could read and modify your variables. By keeping access restricted to the one function it is easier to follow.
You do not. The variables local to a function only exist while that function is running; so once main has returned, its x does not exist. This also ties in to the fact that a separate call to the function gets a separate variable.
What you describe is a bit like reading the value of a static variable in C. The difference with static variables is that they're independent of the call; they still exist, and that makes most functions that use them non-reentrant. Sometimes this is emulated in Python by adding a default argument with a mutable value, with the same downsides.
In CPython, you actually can find out what the local variables of a pure Python function are by inspecting its code object, but their values will only exist in the call itself, normally on a call stack.
def func():
x=2
import dis
print func.__code__.co_varnames
dis.disassemble(func.__code__)
yields:
('x',)
2 0 LOAD_CONST 1 (2)
3 STORE_FAST 0 (x)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
So x is actually local variable 0.
I would suggest looking up a debugger for details on call stack inspection.
Once you start needing attributes on a function, turn it into a functor:
class MainFactory(object):
def __call__(self):
self.x = 4
main = MainFactory() # Create the function-like object main
main() # call it
print main.x # inspect internal attributes
A functor in python is simply a normal object whose class implements the special __call__ method. It can have an __init__ method as well, in which you may pre-set the values of attributes if you wish. Then you can create different "flavours" of your functor by supplying different arguments when instantiating:
class MainFactory(object):
def __init__(self, parameter=1):
self.parameter = parameter
def __call__(self):
self.x = 4 * self.parameter
Now main = MainFactory(2); main() will have main.x set to 8.
Obviously, you can keep unimportant variables of the function inaccessible by simply using local variables instead of attributes of self:
def __call__(self):
# i and p are not accessible from outside, self.x is
for i in range(10):
p = i ** self.parameter
self.x += p
x = 0
def main():
global x
x = 2 # accesses global x
main()
print x # prints 2