Python property object defined outside class __init__ [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 months ago.
Improve this question
I've been going through Python tutorial for Python properties and I can't make any sense of this code:
# using property class
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
# getter
def get_temperature(self):
print("Getting value...")
return self._temperature
# setter
def set_temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible")
self._temperature = value
# creating a property object
temperature = property(get_temperature, set_temperature)
human = Celsius(37)
print(human.temperature)
print(human.to_fahrenheit())
human.temperature = -300
Why is the property being assigned outside of init?
where is self._temperature even defined?
How is self._temperature is linked to self.temperature even though these two are not linked together any where in the code?
How is it that in the to_fahrenheit function, even though that I'm changing self.temperature, it is self._temperature that gets changed not the original temperature that is defined in the constructor?
I'd really appreciate any help since this does not make any sense but works!

Your snippet illustrates the concept of getter and setter methods in Python. When attempting to set the temperature class variable (e.g. human.temperature = -300), Python does not actually modify human.temperature, but calls human.set_temperature(-300) instead, which, given no error is raised, sets human._temperature to the specified value. Similarly, calling print(human.temperature) is equivalent to print(human.get_temperature()) (try these replacements in your code and see what happens).
Moreover, the _ prefix of _temperature signal that it is a private variable, i.e. should not be used outside the class definition and the get_ / set_ prefix declares that the function is a getter / setter.
In conclusion, human.temperature does not hold a value, but rather calls human.get_temperature() or human.set_temperature() depending on the context. The actual value is stored in human._temperature. For a more detailed explanation, I suggest reading the aforementioned articles.

Related

How to use any obtained variable from a function in other functions in Python classes? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 21 days ago.
Improve this question
I am trying to use one variable obtained from one function in other function. However , it gives error. Let me explain it wih my code.
class Uygulama(object):
def __init__(self):
self.araclar()
self.refresh()
self.gateway_find()
def refresh(self):
self.a, self.b = srp(Ether(dst="FF:FF:FF:FF:FF:FF") / ARP(pdst=self.ip_range2), timeout=2, iface="eth0",
retry=3)
#There are unrelated codes here
def gateway_find(self):
#Find ip any range in which you conncet:
self.ip_range=conf.route.route("0.0.0.0")[1]
self.ip_range1=self.ip_range.rpartition(".")[0]
self.ip_range2=self.iprange_1+".0/24"
When , run the foregoing codes , i get this error AttributeError: 'Uygulama' object has no attribute 'ip_range2'
How can i use such variable which are obtained from other function in the other function. How can i fix my problem ?
Call order of init functions
Place function that define attribute first
In the __init__ function, you call refresh, who use (need) ip_range2 before gateway_find who create the attribute and set a value to it. Swap the two lines, you should be fine.
def __init__(self):
self.araclar()
self.gateway_find() # gateway_find will set the ip_range attribute
self.refresh() # So refresh function will be able to access it
Usually, we place init functions first, then function that will call post-init processes like refresh.
Class attribute default value
Alternatively, you can define a default value for ip_range2 like this:
class Uygulama(object):
ip_range2 = None
def __init__(self):
self.araclar()
self.refresh()
self.gateway_find()
def refresh(self):
self.a, self.b = srp(Ether(dst="FF:FF:FF:FF:FF:FF") / ARP(pdst=self.ip_range2), timeout=2, iface="eth0", retry=3)
Be aware that such default value is shared with all other instances of the class if not redefined in __init__, so if it's a mutable (like a list), it might create really weird bugs.
Usually, prefer defining value in the __init__ like you do with the gateway fct.
That error explains correctly that you do not have a class attribute called ip_range2. You need to define the class attribute first.
class Uygulama(object):
ip_range2 = ''
...
then use that with self.ip_range2.

What is the best practice for initializing an instance variable in a class in python? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Below two variants to initialize a class instance variable. What is the best practice for initializing an instance variable in a class in python and why (maybe none of the suggested variants)?
Assumption: variant a because it might be more explicit?
class Example():
def __init__(self, parameter):
# EITHER
# variant a to initialize var_1
self.var_1 = self.initialize_var_1_variant_a(parameter)
# OR
# variant b to initialize var_1
self.initialize_var_1_variant_b(parameter)
# OR something else
# ...
def initialize_var_1_variant_a(self, parameter):
# complex calculations, var_1 = f(parameter)
result_of_complex_calculations = 123
return result_of_complex_calculations
def initialize_var_1_variant_b(self, parameter):
# complex calculations, var_1 = f(parameter)
result_of_complex_calculations = 123
self.var_1 = result_of_complex_calculations
example_instance = Example("some_parameter")
print(example_instance.var_1)
Variant A is the common way to do this. It is very nice to be able to see all of the class members by looking at __init__, instead of having to dive into the other functions (initialize_var_1_variant_b) to find out exactly what attributes are set.
In general, all member attributes that a class will ever have should be initialized in __init__.
To come at it from another angle, initialize_var_1_variant_a should do as little as possible. Calculating the value of var_1 and saving it as a class attribute are two tasks that can be easily broken apart.
It also opens up the possibility of moving initialize_var_1_variant_a outside of the class itself, so it could be re-used by other parts of your program down the line.

Class variable and Instance variable in Python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am practicing python classes. I got that classes variables are shared among all the instances, while instance variables belongs to each object, and thus need to be defined for each instance. In the following classes, in reference to the variable raise_amount, if I write the last code line like that: self.pay = int(self.pay * Employee.raise_amount), the behavior is the same.
What is the difference between the two cases, if any?
class Employee:
raise_amount = 1.04
def __init__(self ,first ,last ,pay ):
self.first = first
self.last = last
self.pay = pay
self.email = first+"."+last+"#company.com"
def apply_raise(self): #but this is not an attribute
self.pay = int(self.pay * self.raise_amount)
#or self.pay = int(self.pay * Employee.raise_amount)
I assume your are referring to the self.raise_amount. In the case where you have it as that python must first look for instance variable and if not found it looks for similarly named class variable and creates a copy of it as an instance variable and uses that. if you were to then change the self.raise amount it would only be for the instance and not for any other instance made from the class.
Try creating an instance of the class and use the apply_raise method on it. then try changing the raise_amount class variable to something like 2.0 and call the method on the instance again. what you should see is that the amount only goes up 1.04 times, not 2. that is because it used the instance value it created the first time you ran the method.
Note: original post was edited to change to use the Class name for the raise amount. This post was a reply while it was self.raise_amount.
The lookup for the expression self.raise_amount can be complicated in general, be we can simplify it knowing that there are no methods or descriptors involved.
If self has an instance attribute named raise_amount, the value of that attribute is returned.
Otherwise, we start looking for class attributes, starting with the immediate type of self, here Employee. Since Employee.raise_amount is defined, we get that value...
... but what if Employee.raise_amount hadn't been defined? We would have moved on to the next class in the method resolution order of Employee, namely object. Since object.raise_amount is not defined, an AttributeError would have been raised.

Which of these is the best practice for accessing a variable in a class? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
If I have an object, and within that object I've defined a variable, which of these methods would be considered 'best' for accessing the variable?
Method One
Using a getter function
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
def get_the_variable(self):
return self.the_variable
if __name__ == "__main__"
a = MyClass()
print(a.get_the_variable())
Method Two
Using the #property decorator
class MyClass:
def __init__(self):
self._the_variable = 21 * 2
#property
def the_variable(self):
return self._the_variable
if __name__ == "__main__"
a = MyClass()
print(a.the_variable)
Method Three
Simply accessing it directly
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
if __name__ == "__main__"
a = MyClass()
print(a.the_variable)
Are any of these methods more pythonic than the others?
Method 3 is the standard pythonic way to start. If you need additional logic, filtering or some other behavior for the attribute you can always go back and add a method for the attribute and use the #property decorator at a later time. That's the beauty of python, start with something simple that works. If you later need finer control over the attribute you can create the property and not have to update/change any of the client code that uses the attribute. The client code will not know the difference between accessing the attribute directly vs calling a method and as a result does not have to change.
This ideology is confirmed via PEP 549
Python's descriptor protocol guides programmers towards elegant API design. If your class supports a data-like member, and you might someday need to run code when changing the member's value, you're encouraged to simply declare it as a simple data member of the class for now. If in the future you do need to run code, you can change it to a "property", and happily the API doesn't change.
I think it's not easy to answer since it's based on the program.
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
def get_the_variable(self):
return self.the_variable
But if you want to pass a class attirubete to some variable, I think it's better to use getter-setter, since it is more readable and understandable. Because you are basically telling I ask this value. For example:
if __name__ == "__main__":
a = MyClass()
modified_variable = a.get_the_variable() * 2
In contrary, if you are just using that class attribute, third option a.the_variable is better.
if a.get_the_variable() == 42:
# do something
else:
# do something

Properties defined with property() and #property [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I am now trying to properly learn Python, and I am really puzzled by existence of two ways to create object properties: using the #property decorator and the property() method. So both of the following are valid:
class MyClassAt:
def __init__(self, value):
self._time = value
#property
def time(self):
return self._time
#time.setter
def time(self, value):
if value > 0:
self._time = value
else:
raise ValueError('Time should be positive')
and
class MyClassNoAt:
def __init__(self, value):
self._time = value
def get_time(self):
return self._time
def set_time(self, value):
if value > 0:
self._time = value
else:
raise ValueError('Time should be positive')
time = property(fget=get_time, fset=set_time)
Is there an agreement which one to use? What would a Pythonista choose?
They are equivalent, but the first one is preferred as many people find it more readable (while also not cluttering the code and the namespace).
The problem with the second method is that you are defining two methods that you will never use, and they remain in the class.
One would use the second method only if they have to support a very old Python version, which does not support decorators syntactic sugar. Function and method decorators were added in Python 2.4 (while class decorators only in version 2.6), so that is in almost all cases a problem of the past.
In the old days (pre python 2.4), the decorator syntax (i.e. #property) didn't exist yet, so the only way to create decorated functions was to use your second method
time = property(fget=get_time, fset=set_time)
The PEP that lead to decorators gives many reasons for the motivation behind the newer syntax, but perhaps the most important is this one.
The current method of applying a transformation to a function or
method places the actual transformation after the function body. For
large functions this separates a key component of the function's
behavior from the definition of the rest of the function's external
interface.
It's much clearer with the newer # syntax that a property exists by simply skimming through the code and looking at the method/property definitions.
Unfortunately, when they first added the new #property decorator, it only worked for decorating a getter. If you had a setter or a deleter function, you still had to use the old syntax.
Luckily, in Python 2.6, they added the getter, setter, and deleter attributes to properties so you could use the new syntax for all of them.
These days, there's really no reason to ever use the old syntax for decorating functions and classes.

Categories

Resources