I understand that __init__() is the constructor for an instance of the class. It is called whenever a class is instantiated. There is also the concept of class variables -- variables that belong to the class and shared by all instances. For example:
class A(object):
a = 1
b = [] #a and b are shared by all instances of class A
But the problem is that sometimes it takes more code to initialize a and b than the one lines showing above. Therefore there is a need for 'class level constructor.' I wonder, though, if there is such a thing.
You can just do something like
class A(object):
# .......
var = input()
var += 10
# ecc.
A.b = var
Related
How can I pass class attribute to a class method so that the attribute will be modified?
class foo:
def __init__(self):
self.diamond = 1
self.gold = 10
self.change(self.diamond)
self.change(self.gold)
def change(self, x):
x+=1
model = foo()
print(model.diamond)
output:
1
I want diamond becomes 2.
Is this a good solution for you?
class foo:
def __init__(self):
self.diamond = 1
def change(self):
self.diamond += 1
model = foo()
model.change()
print(model.diamond)
Let me say this first that you have no class method, or class variable in your example. What you have are instance variables and instance methods, note the self keyword. Now, with that said, you can access and modify your instance variables from any instance method, just like #Almog answered earlier.
The x in your change method is a local variable, basically it's not available outside your method. As for how you modify a variable by passing it to a function, it's not doable with your code I think. You would need something like a dataclass, which you can modify. Check out 'PassByValue' and 'PassByReference' concepts relating to this. Maybe someone else here can help with your particular situation.
Look at the code below.
class A :
def __init__(self, a = "Hello") :
self.a = a
print(A().a) # 1
print(A.a) # 2
1 is not error
2 is error - AttributeError: type object 'A' has no attribute 'a'
What is the difference between the two results?
In your code A refers the the type of a class and also to its constructor/initialiser. A is called the class and when you construct an object of type A with the constructor you get an instance of that class.
A # Refers to the class A
A() # is an instance of class A
There is a difference between a class property and an instance property. Consider the following code:
class A:
propertyA = "hello"
def __init__(self, string="world"):
self.propertyB = string
In this snippet propertyA is a class property while propertyB is an instance property. Each instance of type A has its own propertyB and you must instantiate and object (an instance) first.
A.propertyA # Class property, does not need an instance
A().propertyB # instance property, needs an instance
In your code the constructor for A is the code written in the __init__. This code will be called when you type A(). Note that you specified a default value for the parameter a but if you don't you would call the constructor like this:
A("hello") # or:
A(a="hello")
Note that classes, instances and constructors are fundamentals of OOP (and by extension Python), you really should learn this, it avoids lots of basic errors.
You need to create an instance of the class first:
class A :
def __init__(self, a = "Hello") :
self.a = a
class_instance = A()
print(class_instance.a)
You can set the value of "a" when creating the instance by typing in the parenthesis:
class_instance = A("this is the value of a")
you can change the value after the creation like so:
class_instance.a = "New value of a"
A().a is creating an instance and returns the a value of the instance.
A.a cannot be executed because A is the Class name and doesn't have any attributes if you don't create an instance first
I'm stuck on this point about class inheritance, and I haven't been able to figure out a clean way forward. I have some base class:
class Foo:
""" Parent class. """
def __init__(self,a,b):
self.a = a
self.b = b
def product(self):
return self.a * self.b
This class contains information I've loaded in from some data file. I want to generate different kinds of information related to this data, using class properties to store that information. For example, if I wanted to create a report that tells me the quotient of a and b, I would want to create something like:
class Bar(Foo):
""" Child class. """
def __init__(self,foo_object):
# What I want to avoid:
self.a = foo_object.a
self.b = foo_object.b
def quotient(self):
return self.a / self.b
Obviously there are many more class properties in my real application. It becomes very tedious to assign all of the properties from the Foo object into the new Bar object.
Is there a more elegant way to "extend" a Foo object into a Bar object once the Foo object has already been created?
EDIT:
Sorry if I didn't state my objective clearly enough; I see that there's some confusion about what I'm asking for. I've already created a Foo object with a number of properties. I want to create a child class of Foo, called Bar, later, that contains those properties but also some additional properties that are specific to one "area" of my application.
So, I want to be able to pass in an already instantiated Foo object, and pass the values of its properties into identical properties in Bar, without doing this manually item-by-item.
I believe Flob's answer is what I'm looking for. Thank you!
You can inherit the Information directly by initiating the parent class inside the child class. Once you have created an instance of the parent class, you can Access all it's properties by using vars(object), which will return a dictionary of all properties assiciated with the object. For example, let's say you have a class Foo:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
and test_parent is an instance of this class.
test_parent = Foo(a='Hello', b='World')
now, when creating the Bar child class, do it like this:
class Bar(Foo):
def __init__(self, foo_object):
a, b = vars(foo_object).values() #get all properties of parent class object
Foo.__init__(self, a, b) # initiate parent class
def say_hello(self):
print('{} {}'.format(self.a, self.b))
Create an instance of the Bar class and call say_hello:
test_child = Bar(test_parent)
test_child.say_hello()
Output:
"Hello World"
I'm not sure I understand what you mean by "once the Foo object has already been created".
For initialization of the attributes defined by the parent class, use this:
class Bar(Foo):
""" Child class. """
def __init__(self,a,b):
super().__init__(a,b)
def quotient(self):
return self.a / self.b
Let the __init__() method of the super-class continue to do its job of initializing a and b.
Note that b = B() creates only one object, not two.
In the code you posted, Bar.__init__() seems to take a Foo object as one of its arguments. Technically, that is a case of wrapping a Foo object in a Bar object -- and if you're doing that, there really is no need for Bar to be a child class of Foo:
class Bar:
""" Wrapper class. """
def __init__(self, foo_object):
self.foo_object = foo_object
def quotient(self):
return self.foo_object.a / self.foo_object.b
It is possible to change the class of the object after it is created. Instead of unpacking the contents of the object into a new one, you change the class that it uses to look up methods:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
def quotient(self):
return self.a/self.b
f = Foo(1, 2)
f.__class__ = Bar
f.quotient() # 0.5
This usually isn't necessary (I woudln't recommend using it here). Instead, you could create a Bar object directly:
b = Bar(1, 2)
b.quotient()
Bar inherits the __init__ method of Foo, so you don't have to redefine it.
Another option is to use a function that's not a method:
def quotient(obj):
return obj.a/obj.b
Now you can compute quotient(Foo(1,2)) even though your Foo object doesn't know about the quotient function.
A class can inherit from a base class, but an object cannot inherit from another object. It can either be a copy (with possibly additional attributes) or wraps the original object. The first case is for a true inheritance strategy (the child instance has to be an instance of the base class and must initialize itself), the second if for an aggregation or containment strategy.
But beware, there are some caveats with the second one, mainly because the child object is not an instance of the base class (isinstance(child, Foo) is false). That means that there is no one size fits all way here, and you will have to choose one pattern, inheritance vs aggregation.
Let B inherit from A. Suppose that some of B's behavior depends on the class attribute cls_x and we want to set up this dependency during construction of B objects. Since it is not a simple operation, we want to wrap it in a class method, which the constructor will call. Example:
class B(A):
cls_x = 'B'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = B.cm()
Problem: cm as well as __init__ will always be doing the same things and their behavior must stay the same in each derived class. Thus, we would like to put them both in the base class and not define it in any of the derived classes. The only difference will be the caller of cm - either A or B (or any of B1, B2, each inheriting from A), whatever is being constructed. So what we'd like to have is something like this:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = ClassOfWhateverIsInstantiated.cm() #how to do this?
class B(A):
cls_x = 'B'
I feel like it's either something very simple I'm missing about Python's inheritance mechanics or the whole issue should be handled entirely differently.
This is different than this question as I do not want to override the class method, but move its implementation to the base class entirely.
Look at it this way: Your question is essentially "How do I get the class of an instance?". The answer to that question is to use the type function:
ClassOfWhateverIsInstantiated = type(self)
But you don't even need to do that, because classmethods can be called directly through an instance:
def __init__(self):
self.attr = self.cm() # just use `self`
This works because classmethods automatically look up the class of the instance for you. From the docs:
[A classmethod] can be called either on the class (such as C.f()) or on an instance
(such as C().f()). The instance is ignored except for its class.
For ClassOfWhateverIsInstantiated you can just use self:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = self.cm() # 'self' refers to B, if called from B
class B(A):
cls_x = 'B'
a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'
b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'
To understand this, just remember that class B is inheriting the methods of class A. So when __init__() is called during B's instantiation, it's called in the context of class B, to which self refers.
So I am recently new to Python, but I seem to be able to program some stuff and get it working. However I've been trying to expand my knowledge of how things work in the language, and putting this simple file together confuses me.
class TestA:
def __init__(self):
self.varNum = 3
def printNum(self):
print(self.varNum)
class TestB:
varNum = 0
def __init__(self):
varNum = 3
def printNum(self):
global varNum
print(varNum)
a = TestA()
a.printNum()
b = TestB()
b.printNum()
The code to TestA prints 3 to the screen properly. However the code for TestB instead gives me a NameError stating that: 'varNum' is not defined. And I get that error whether i have the global varNum line there or not.
I suppose what confuses me, is I see the __init__ function as a class constructor. And when I have programmed with languages such as Java or C# I've declared global variables outside of the constructor so that their scope is the whole class. Is that not a thing in Python? The code I've written I just kind of tagged self. onto everything because I was just trying to get some stuff put together quickly, but I am trying to figure more out about the language now. Is self. the only way in Python to make class scope variables? Or are there other ways?
Thanks for your time :)
In Python, variables declared inside the class definition, but not inside a method are class or static variables:
class TestB:
varNum = 0
This creates a class-level varNum variable, but this is distinct from any instance-level varNum variable, so you could have:
class TestB:
varNum = 0
def __init__(self):
self.varNum = 3
b = TestB()
print(b.varNum) # print 3
print(TestB.varNum) # print 0
Thus, class TestB should work in this way:
class TestB:
varNum = 0
def __init__(self):
self.varNum = 3
def printInstanceNum(self):
print(self.varNum)
def printClassNum():
print(TestB.varNum)
b = TestB()
b.printInstanceNum() # print 3
TestB.printClassNum() # print 0
Note that since there's no any reference to instance object in method printClassNum(), we don't have to put self as an argument. The method could actually become a staticmethod:
class TestB:
varNum = 0
#staticmethod
def printClassNum():
print(TestB.varNum)
Ref
class objects
static method