Self in init params
Instead of using Self
or A
in each of the initialisers, you can simply override each subclass' initialiser to use its own type as operation
.
This works because A
's initialiser states that operation
should be a type that conforms to A
, and when you override it you have the liberty to use a subclass of A
as operation
instead. However, if you change operation
to an unrelated type such as String
or Int
, the compiler will not override the existing initialiser.
Firstly, define A
with its init
:
class A {
init(finishBlock: ((_ operation: A) -> Void)?) {...}
}
Now to create a subclass, you must override init
using the subclass' type as operation
instead. In your call to super.init
, force upcast operation
($0
) to your subclass' type, and call finishBlock
with this casted operation
.
class B: A {
override init(finishBlock: ((_ operation: B) -> Void)?) {
// Perform custom initialisation...
super.init { finishBlock?($0 as! B) }
}
func fooOnlyInB() {
print("foo")
}
}
B
's initialiser now passes B
as operation
, which means that you don't need to cast it yourself anymore! This is thanks to the fact that you can override an init
with a more specific type, in this case B
.
let b = B { operation in
operation.fooOnlyInB() // prints "foo"
}
Using self in init part of a class in Python
No. there is no difference between these two approaches in your case with this level of information. but could they? Yes. they could. if they have some modifications in their setters or getters. later in my answer I'll show you how.
First of all, I prefer using this one:
class summation:
def __init__(self, f, s):
self.first = f
self.second = s
@property
def summ(self):
return self.first+self.second
the above implementation calculates the summation on demand. so when you change self.first
or self.second
, summ
will be calculated automatically. you can access the sum as you did before.
s = summation(1,9)
print(s.summ)
# 10
s.first = 2
s.second = 3
print(s.summ)
# 5
So, How could they be different?
let's implements them as follows. in setters I doubled the inputs to show you how setters can affect the results. it's just an imaginary example and is not exactly what you wrote.
class summation1:
def __init__(self, f, s):
self.first = f
self.second = s
self.summ = self.first + self.second
@property
def first(self):
return self.__first
@first.setter
def first(self,f):
self.__first = f*2
@property
def second(self):
return self.__second
@second.setter
def second(self,s):
self.__second = s*2
class summation2:
def __init__(self, f, s):
self.first = f
self.second = s
self.summ = f + s
@property
def first(self):
return self.__first
@first.setter
def first(self,f):
self.__first = f*2
@property
def second(self):
return self.__second
@second.setter
def second(self,s):
self.__second = s*2
now let's take a look at the outputs:
a = 3
b = 2
s1 = summation1(a,b)
s2 = summation2(a,b)
print(s1.summ)
# 10
print(s2.summ)
# 5
so, if you are not sure what to choose between those two, maybe the first approach is what you need.
How to get class of object being created in __init__ parameters
I think that you should put it in the body, not the parameter.
def __init__(self, foo):
self.foo = foo
self.bar = type(self).some_class_variable
self.ham = self.some_function(type(self).some_other_class_variable)
EDIT:
If the values are defaults, you can do this:
default_value = 'default pls'
def __init__(self, foo, bar=default_value, ham=default_value):
self.foo = foo
if default_value == bar:
self.bar = type(self).some_class_variable
if default_value == ham:
self.ham = self.some_function(type(self).some_other_class_variable)
Adding parameters to init and create instance
You never define self.speed_top_border
, self.speed_bottom_border
in your __init__
, but try to use them in self.obstacleX_change = random.uniform(self.speed_top_border, self.speed_bottom_border)
If you want to have these attributes - define them, before using them
class Obstacle(object):
def __init__(self, speed_top_border, speed_bottom_border):
self.obstacleImg = 'rock.png'
self.obstacleX = random.randint(700, 800)
self.obstacleY = random.randint(0, ScreenHeight - 64)
self.speed_top_border = speed_top_border
self.speed_bottom_border = speed_bottom_border
self.obstacleX_change = random.uniform(self.speed_top_border, self.speed_bottom_border)
Python Class __init__ Confirmation
Firstly: The __init__()
function is special in that it is called for you while creating a new instance of a class. Apart from that, it is a function like any other function, you can even call it manually if you want.
Then: You are free to do what you want with the parameters passed to a function. Often, the parameters passed to __init__()
are stored inside the object (self
) that is being initialized. Sometimes, they are used in other ways and the result then stored in self
, like passing a hostname and using that to create a socket - you then only store the socket. You don't have to do anything with the parameters though, you can ignore them like you do in your First()
function, which receives a parameter name
which is ignored. Note that this parameter name
and the similar attribute self.name
are different things!
Notes:
- It is uncommon to ignore parameters passed to
__init__()
though, just as it is uncommon to ignore parameters in general. In some cases, they are "reserved" so they can be used by derived classes but typically they are unintended (as with yourFirst()
function, I guess). - Check out PEP8, which is a style guide. Adhering to it will make it easier for others to read your code. E.g.
First()
should befirst()
instead. - Upgrade to Python 3. I don't think there's any excuse nowadays to learn Python 2 and littley excuse except maintenance to use it in general.
Python class's init function takes instance of own class as default parameter
You should do this:
class Node:
def __init__(self, name, visited=False, distance=math.inf, path=None):
self.name = name
self.visited = visited
self.distance = distance
if path is None:
self.path = Node('-', path="default-path")
else:
self.path = path
This is the idiom you should be following with mutable default arguments to begin with.
However, you need the default to have a path, or it will recurse without stopping.
Why isn't my class initialized by def __int__ or def _init_ ? Why do I get a takes no arguments TypeError, or an AttributeError?
What do the exception messages mean, and how do they relate to the problem?
As one might guess, a TypeError
is an Error
that has to do with the Type
of something. In this case, the meaning is a bit strained: Python also uses this error type for function calls where the arguments (the things you put in between ()
in order to call a function, class constructor or other "callable") cannot be properly assigned to the parameters (the things you put between ()
when writing a function using the def
syntax).
In the examples where a TypeError
occurs, the class constructor for Example
does not take arguments. Why? Because it is using the base object
constructor, which does not take arguments. That is just following the normal rules of inheritance: there is no __init__
defined locally, so the one from the superclass - in this case, object
- is used.
Similarly, an AttributeError
is an Error
that has to do with the Attribute
s of something. This is quite straightforward: the instance of Example
doesn't have any .attribute
attribute, because the constructor (which, again, comes from object
due to the typo) did not set one.
Why didn't a problem occur earlier, for example, with the class definition itself?
Because the method with a wrongly typed name is still syntactically valid. Only syntax errors (reported as SyntaxError
; yes, it's an exception, and yes, there are valid uses for it in real programs) can be caught before the code runs. Python does not assign any special meaning to methods named _init_
(with one underscore on each side), so it does not care what the parameters are. While __int__
is used for converting instances of the class to integer, and shouldn't have any parameters besides self
, it is still syntactically valid.
Your IDE might be able to warn you about an __int__
method that takes suspicious parameters (i.e., anything besides self
). However, a) that doesn't completely solve the problem (see below), and b) the IDE might have helped you get it wrong in the first place (by making a bad autocomplete suggestion).
The _init_
typo seems to be much less common nowadays. My guess is that people used to do this after reading example code out of books with poor typesetting.
How else might the problem manifest?
In the case where an instance is successfully created (but not properly initialized), any kind of problem could potentially happen later (depending on why proper initialization was needed). For example:
BOMB_IS_SET = True
class DefusalExpert():
def __int__(self):
global BOMB_IS_SET
BOMB_IS_SET = False
def congratulate(self):
global BOMB_IS_SET
if BOMB_IS_SET:
raise RuntimeError("everything blew up, gg")
else:
print("hooray!")
If you intend for the class to be convertible to integer and also wrote __int__
deliberately, the last one will take precedence:
class LoneliestNumber:
def __int__(self):
return 1
def __int__(self): # was supposed to be __init__
self.two = "can be as bad"
>>> int(LoneliestNumber())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __int__ returned non-int (type NoneType)
(Note that __int__
will not be used implicitly to convert instances of the class to an index for a list or tuple. That's done by __index__
.)
How might I guard against the problem in the future?
There is no magic bullet. I find it helps a little to have the convention of always putting __init__
(and/or __new__
) as the first method in a class, if the class needs one. However, there is no substitute for proofreading, or for training.
Related Topics
Get Button Pressed Id on Swift Via Sender
Multiple Workers in Swift Command Line Tool
App Tracking Transparency Dialog Does Not Appear on iOS
How to Create Custom Notifications in Swift 3
Dispatchsourcetimer and Swift 3.0
How to Left Align the Title of a Navigation Bar in Xcode
Perform Assignment Only If Right Side Is Not Nil
Trouble Using Callbacks with Cgpattern in Swift3
What Versions of Swift Are Supported by What Versions of Xcode
Ios13 Navigation Bar Large Titles Not Covering Status Bar
Swift: Failing to Copy Files to a Newly Created Folder
Function with Datatask Returning a Value
How to Create Swift Class for Category
Programmatically Navigate to New View in Swiftui
Every Uialertcontroller Disappear Automatically Before User Responds - Since iOS 13
Handling Multiple Gesturerecognizers
Uitableviewautomaticdimension Not Working for Resizing Cell Height