Python: confused with classes, attributes and methods in OOP - python

I'm learning Python OOP now and confused with somethings in the code below.
Questions:
def __init__(self, radius=1):
What does the argument/attribute "radius = 1" mean exactly?
Why isn't it just called "radius"?
The method area() has no argument/attribute "radius".
Where does it get its "radius" from in the code?
How does it know that the radius is 5?
class Circle:
pi = 3.141592
def __init__(self, radius=1):
self.radius = radius
def area(self):
return self.radius * self.radius * Circle.pi
def setRadius(self, radius):
self.radius = radius
def getRadius(self):
return self.radius
c = Circle()
c.setRadius(5)
Also,
In the code below, why is the attribute/argument name missing in the brackets?
Why was is not written like this: def __init__(self, name)
and def getName(self, name)?
class Methods:
def __init__(self):
self.name = 'Methods'
def getName(self):
return self.name

The def method(self, argument=value): syntax defines a keyword argument, with a default value. Using that argument is now optional, if you do not specify it, the default value is used instead. In your example, that means radius is set to 1.
Instances are referred to, within a method, with the self parameter. The name and radius values are stored on self as attributes (self.name = 'Methods' and self.radius = radius) and can later be retrieved by referring to that named attribute (return self.name, return self.radius * self.radius * Circle.pi).
I can heartily recommend you follow the Python tutorial, it'll explain all this and more.

def __init__(self, radius=1):
self.radius = radius
This is default value setting to initialize a variable for the class scope.This is to avoid any garbage output in case some user calls c.Area() right after c = Circle().
In the code below, why is the attribute/argument "name" missing in the brackets?
In the line self.name = 'Methods' you are creating a variable name initialized to string value Methods.
Why was is not written like this: def init(self, name) and def
getName(self, name)?
self.name is defined for the class scope. You can get and set its value anywhere inside the class.

The syntax radius = 1 specifies a parameter "radius" which has a default value of 1:
def my_func(param=1):
... print(param)
...
my_func() #uses the default value
1
my_func(2) #uses the value passed
2
Note that in python there exists more kinds of parameters: positional and keyword parameters, or both.
Usually parameters can be assigned both using the positional notation and the keyword:
>>> def my_func(a,b,c):
... print (a,b,c)
...
>>> my_func(1,2,3)
(1, 2, 3)
>>> my_func(1,2,c=3)
(1, 2, 3)
Python uses "explicit" instance passing, so the first self parameter is used to pass the instance on which the methods are called. You can think of self as being the this of Java. But you must always use it to access instance attributes/methods. You can't call just area(), you must say self.area().
When you do self.attribute = 1 you create a new attribute attribute with value 1 and assign it to the instance self. So in the area() method self.radius refers to the radius attribute of the self instance.
The __init__ method is a special method. It's something similar to a constructor.
It is called when you instantiate the class. Python has a lot of these "special methods", for example the method __add__(self, other) is called when using the operator +.

Related

Is it possible to initialize the argument of a method with a self.variable value from __init__ in python?

I have a class with an __init__ method where I define some variables, as well as a method AddSignalSpectrum:
class SpectrumGraph:
# Properties
def __init__(self):
self.PlotHeight= 300
self.PlotWidth = 800
self.xRangeMin = -10
self.xRangeMax = 10
self.yRangeMin = -0.1*(self.xRangeMax - self.xRangeMin)
self.yRangeMax = 0.9*(self.xRangeMax -self.xRangeMin)
def AddSignalSpectrum(
self,
name,
Type,
CenterPosition,
Bandwidth=2,
Height = self.yRangeMax*0.8,
Color = "#0000FF",
LineWidth = 2,
AbscissaSymbol = '$\omega_0$',
ShowLegend = False):
# Rest of the method
What I want is to provide the default value of self.yRangeMax*0.8 to the method but when I do that I get an error saying that 'self' is not defined. I can use attributes of self inside the method just fine, but it does not seem to work within the arguments of the method definition. I assume this is some sort of name space problem but can't find a workaround. It could be I'm just not sure what exactly to search for.
This is not initialization, it is setting defaults for function parameters. The problem isn't to do with namespaces, it's to do with binding.
These values are determined once, ahead of time and are stored as part of the function (or method) object. It is not possible to use attributes of the self parameter here because there isn't one at the time that this happens. It is the same thing with ordinary functions:
def example(a, b=a+3): # doesn't work; `a` is not defined ahead of time
print(f'a={a} and b={b}')
The normal workaround for this is to use None as the default value, and then explicitly check for this in the logic and replace None with the desired calculation:
def example(a, b=None): # works
if b is None:
b = a + 3
print(f'a={a} and b={b}')
# and now we can call:
example(1) # 'a=1 and b=4'
The usual way to do this is to set a sentinel value (idiomatically None) and then define behavior inside the method, e.g.:
def Dog:
def __init__(self, name, friend):
self.name = name
self.friend = friend
def say_hello(self, other=None):
if other is None:
other = self.friend
print(f"Hello {other}, I'm {self.name}! How are you? Bark!")

Convention for referencing class attributes?

What is the convention for referencing class attributes? I understand that there are two ways of referencing class attributes:
class Circle1:
pi = 3.14
def __init__(self, radius=1):
self.radius = radius
def get_circumference():
return 2 * self.pi * self.radius
class Circle2:
pi = 3.14
def __init__(self, radius=2):
self.radius = radius
def get_circumference():
return 2 * Circle2.pi * self.radius
The first way is referencing it as self.attribute, while the second way is to reference it as Class.attribute. Which way is the convention for referencing class attributes? Or is there no convention and is it just a matter of preference?
It really depends on how you're going to use it. Class.attribute will set it as an attribut for all instances of that class, while self.attribute is only for specific instances. In your case, pi is always (around) 3.14, so it should be a class attribute, while the radius is specific to any one circle, so it should be set as self.radius.
Also, to help shorten your code, you should only use 1 class of circles, and make the radius mandatory (don't specify default) because that is the only thing that changes.

Calling class-specific method from another class

I am working in a class called AlgoSystem, which is given strategy_0 and strategy_1 as inputs under initialization as well as the number of strategies (2 in this case). The strategy classes are stored in a dictionary called "strategies" within the AlgoSystem. Both strategy_0 and strategy_1 are different classes themselves, but both with a function called "__on_tick". These functions I want to call from within the AlgoSystem class.
My current attempt to do this is seen below:
class AlgoSystem:
def __init__(self, strategy_0, strategy_1, numstrategies):
self.var= 1
self.strategies = {0 : strategy_0,
1 : strategy_1}
self.num_strategies = numstrategies
def start(self):
for i in range(self.num_strategies):
self.strategies[i].__on_tick(self.var)
class Strategy_zero:
def __init__(self, x):
self.x = x
def __on_tick(self, var):
self.x = self.x + var
print(self.x)
class Strategy_one:
def __init__(self, y):
self.y = y
def __on_tick(self, var):
self.y = self.y - var
print(self.y)
strategy_0 = Strategy_zero(2)
strategy_1 = Strategy_one(4)
num_strategies = 2
system = AlgoSystem(strategy_0, strategy_1, 2)
system.start()
When I run the code above, I am given the error:
Strategy_zero' object has no attribute '_AlgoSystem__on_tick'
Apparently I'm not calling the class-functions "__on_tick" properly. How should I do this? I need to do it in a way, so I keep track on the changes of the two sub-classes (strategy_0 and strategy_1) through my defined dictionary within AlgoSystem: "strategies".
The double underscore prefix is specifically designed to prevent you from doing exactly what you are doing.
There is no reason for you to use it here. Remove the prefix and can your methods just on_tick.
Double underscore names are hidden names (hidden by obfuscation). I suggest having your on_tick method be called on_tick and try again.
The following code might help clarify what's going on with name-mangling.
class A:
def __mangled(self):
print "Class A name-mangled method"
class B:
def __init__(self):
a = A()
try:
a.__mangled()
except AttributeError:
# an attempt to access a name-mangled method assumes that
# the '_{class_name}' prefix should use 'B' as the class name
print "A instance has no attribute '_B__mangled'"
a._A__mangled()
# prints "Class A name-mangled method"
getattr(a, '_{}__mangled'.format(a.__class__.__name__))()
# same thing, but can be done without knowing the class name
B()
So, you could update self.strategies[i].__on_tick(self.var) to be:
strat = self.strategies[i]
getattr(strat, '_{}__on_tick'.format(strat.__class__.__name__)(self.var)
But, it would probably be best to not precede __on_tick with a double-underscore since it is intended to be accessed outside the class/instance.

Python - Should I use read-only #property without init or setter?

Trying to get my head around property decorators. I found a solution posted for setting read-only attributes here. Setting a private attribute and then providing a #property getter method makes sense if you can specify the attribute in init. But what about the case where you want to use a function to calculate a read-only attribute? Let's say you have a class that calls an attribute (e.g. state) from another class and then calculates a new value that will be made available as an attribute:
class MyState(object):
def __init__(self, starting_value):
self._foo = starting_value
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, value):
self._foo = value
class MyClass(object):
def __init__(self, name=None):
self.name = name
#property
def bar(self):
state = MyState.foo
return id(state)
>mystate = MyState('chuff')
>myclass = MyClass()
>myclass.bar = 183097448L
In everything I have seen about property decorators, I have only see display methods reflected in the #property getter function, never functions that set the value of the variable. However, from reading the docs my understanding is that #setter requires an argument, which I don't have in this case. Is there any problem with calculating the read-only value of a class attribute in the #property getter method as opposed to simply passing an attribute that already exists?
There is no problem. #property is just doing less than you think. All it is is a bit of syntactic sugar to replace: a = foo.x with a = foo.x.getter(), and foo.x = bar with foo.x.setter(bar). That is, it allows you to replace attribute access with method calls. Those methods are allowed to do anything they like, which is the purpose of the property. I think you were being led astray by your first example where the property just passes through to an underlying hidden variable to make a psuedo-read-only variable. That is not really the standard use case. A very common example might be:
class Rectangle(object):
def __init__(self, w, h):
self.w = w
self.h = h
#property
def area(self):
return self.w * self.h
Area is a property of a rectangle, but it is derived from the width and height, and setting it doesn't really make any sense.

What's an example use case for a Python classmethod?

I've read What are Class methods in Python for? but the examples in that post are complex. I am looking for a clear, simple, bare-bones example of a particular use case for classmethods in Python.
Can you name a small, specific example use case where a Python classmethod would be the right tool for the job?
Helper methods for initialization:
class MyStream(object):
#classmethod
def from_file(cls, filepath, ignore_comments=False):
with open(filepath, 'r') as fileobj:
for obj in cls(fileobj, ignore_comments):
yield obj
#classmethod
def from_socket(cls, socket, ignore_comments=False):
raise NotImplemented # Placeholder until implemented
def __init__(self, iterable, ignore_comments=False):
...
Well __new__ is a pretty important classmethod. It's where instances usually come from
so dict() calls dict.__new__ of course, but there is another handy way to make dicts sometimes which is the classmethod dict.fromkeys()
eg.
>>> dict.fromkeys("12345")
{'1': None, '3': None, '2': None, '5': None, '4': None}
I don't know, something like named constructor methods?
class UniqueIdentifier(object):
value = 0
def __init__(self, name):
self.name = name
#classmethod
def produce(cls):
instance = cls(cls.value)
cls.value += 1
return instance
class FunkyUniqueIdentifier(UniqueIdentifier):
#classmethod
def produce(cls):
instance = super(FunkyUniqueIdentifier, cls).produce()
instance.name = "Funky %s" % instance.name
return instance
Usage:
>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
0
>>> y.name
Funky 1
The biggest reason for using a #classmethod is in an alternate constructor that is intended to be inherited. This can be very useful in polymorphism. An example:
class Shape(object):
# this is an abstract class that is primarily used for inheritance defaults
# here is where you would define classmethods that can be overridden by inherited classes
#classmethod
def from_square(cls, square):
# return a default instance of cls
return cls()
Notice that Shape is an abstract class that defines a classmethod from_square, since Shape is not really defined, it does not really know how to derive itself from a Square so it simply returns a default instance of the class.
Inherited classes are then allowed to define their own versions of this method:
class Square(Shape):
def __init__(self, side=10):
self.side = side
#classmethod
def from_square(cls, square):
return cls(side=square.side)
class Rectangle(Shape):
def __init__(self, length=10, width=10):
self.length = length
self.width = width
#classmethod
def from_square(cls, square):
return cls(length=square.side, width=square.side)
class RightTriangle(Shape):
def __init__(self, a=10, b=10):
self.a = a
self.b = b
self.c = ((a*a) + (b*b))**(.5)
#classmethod
def from_square(cls, square):
return cls(a=square.length, b=square.width)
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
#classmethod
def from_square(cls, square):
return cls(radius=square.length/2)
The usage allows you to treat all of these uninstantiated classes polymorphically
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle):
this_shape = polymorphic_class.from_square(square)
This is all fine and dandy you might say, but why couldn't I just use as #staticmethod to accomplish this same polymorphic behavior:
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
#staticmethod
def from_square(square):
return Circle(radius=square.length/2)
The answer is that you could, but you do not get the benefits of inheritance because Circle has to be called out explicitly in the method. Meaning if I call it from an inherited class without overriding, I would still get Circle every time.
Notice what is gained when I define another shape class that does not really have any custom from_square logic:
class Hexagon(Shape):
def __init__(self, side=10):
self.side = side
# note the absence of classmethod here, this will use from_square it inherits from shape
Here you can leave the #classmethod undefined and it will use the logic from Shape.from_square while retaining who cls is and return the appropriate shape.
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
this_shape = polymorphic_class.from_square(square)
I find that I most often use #classmethod to associate a piece of code with a class, to avoid creating a global function, for cases where I don't require an instance of the class to use the code.
For example, I might have a data structure which only considers a key valid if it conforms to some pattern. I may want to use this from inside and outside of the class. However, I don't want to create yet another global function:
def foo_key_is_valid(key):
# code for determining validity here
return valid
I'd much rather group this code with the class it's associated with:
class Foo(object):
#classmethod
def is_valid(cls, key):
# code for determining validity here
return valid
def add_key(self, key, val):
if not Foo.is_valid(key):
raise ValueError()
..
# lets me reuse that method without an instance, and signals that
# the code is closely-associated with the Foo class
Foo.is_valid('my key')
Another useful example of classmethod is in extending enumerated types. A classic Enum provides symbolic names which can be used later in the code for readability, grouping, type-safety, etc. This can be extended to add useful features using a classmethod. In the example below, Weekday is an enuerated type for the days of the week. It has been extended using classmethod so that instead of keeping track of the weekday ourselves, the enumerated type can extract the date and return the related enum member.
from enum import Enum
from datetime import date
class Weekday(Enum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
#
#classmethod
def from_date(cls, date):
return cls(date.isoweekday())
Weekday.from_date(date.today())
<Weekday.TUESDAY: 2>
Source: https://docs.python.org/3/howto/enum.html
in class MyClass(object):
'''
classdocs
'''
obj=0
x=classmethod
def __init__(self):
'''
Constructor
'''
self.nom='lamaizi'
self.prenom='anas'
self.age=21
self.ville='Casablanca'
if __name__:
ob=MyClass()
print(ob.nom)
print(ob.prenom)
print(ob.age)
print(ob.ville)

Categories

Resources