I'm working with kivy on python2.7. As far as I know, self is not a real argument but a tool to use in the function, when working with the parent data. Yet in the following use, python thinks self is a real argument. Is this because I'm calling it in the function?
class Verdo(BoxLayout):
defualtval = ""
tarih = StringProperty(str(datetime.datetime.now()).split(".")[0])
istipitxt = StringProperty(defualtval)
iscitxt = StringProperty(defualtval)
iskodtxt = StringProperty(defualtval)
baslabittxt = StringProperty(defualtval)
parcanotxt = StringProperty(defualtval)
def start(self):
Clock.schedule_interval(self.callback, 0.5)
def callback(self, dt):
print "testo"
self.tarih = StringProperty(str(datetime.datetime.now()).split(".")[0])
start()
#Clock.schedule_interval((lambda dt: updater(), 1), 0.5)
#Clock.schedule_interval((lambda dt: tell(), 1), 0.5)
When the code is run, following error happens:
2015-04-07 22:05:03.081739
Traceback (most recent call last):
File "/home/toshy/workspace/Verdo_reborn/main.py", line 28, in <module>
class Verdo(BoxLayout):
File "/home/toshy/workspace/Verdo_reborn/main.py", line 79, in Verdo
start()
TypeError: start() takes exactly 1 argument (0 given)
I also tried an simpler approach which also failed:
def callback(self, dt):
print "testo"
self.tarih = StringProperty(str(datetime.datetime.now()).split(".")[0])
Clock.schedule_interval(callback, 0.5)
output:
ret = callback(self._dt)
TypeError: callback() takes exactly 2 arguments (1 given)
You should be calling:
self.start()
self is a real argument, but it's supplied automatically as the object on which the method was called.
There are two different contexts in which you might want to call .start(). The first is after instantiating an object of type Verdo:
my_verdo = Verdo()
my_verdo.start()
Alternatively, you may be calling from inside the code for Verdo. In that case you need to specify that your're operating on the current instance.
You should do something like this:
class Verdo(BoxLayout):
defualtval = ""
tarih = StringProperty(str(datetime.datetime.now()).split(".")[0])
istipitxt = StringProperty(defualtval)
iscitxt = StringProperty(defualtval)
iskodtxt = StringProperty(defualtval)
baslabittxt = StringProperty(defualtval)
parcanotxt = StringProperty(defualtval)
def start(self):
Clock.schedule_interval(self.callback, 0.5)
def callback(self, dt):
print "testo"
self.tarih = StringProperty(str(datetime.datetime.now()).split(".")[0])
if __name__ == '__main__':
verdoInstance = Verdo()
verdoInstance.start()
This is just an example, if you want test your code quickly as a single executable python script.
Your error was you tried to call your class method without calling constructor right in your class code. In this case method class really was waiting self (object ref) as a first argument, but the object wasn`t created at that time.
Related
i'm trying to solve the adventofcode riddles, but this year i decided to take the chance to learn a new programming language: Python.
Since i already have some knowledge about other OOP languages like Java and C++, i immediately created an "interface" system for the Solutions objects.
My project setup at the moment is like:
Project Setup
Now what i want is to dynamically output solutions through the main class, that basically has to call all .solve() method of each dayX.py class that is in the /solutions/ directory.
I think i'm next to do it but i get an error:
Traceback (most recent call last):
File "C:\Users\siste\j-workspace\adventofcode2020\main.py", line 16, in <module>
print(solution.solve())
TypeError: solve() missing 1 required positional argument: 'self'
Here are my files:
main.py
import os
def days():
classes = []
path = "C:\\path"
for file in os.listdir(path):
if(file.startswith("day")) :
classes.append(str(file.replace(".py", "")))
return classes
if __name__ == '__main__':
for day in days() :
solution = getattr(__import__(str("solutions." + day)), day.replace("d", "D"))
print(solution.solve())
solution.py
path = "C:\\path\\inputs\\day{}.txt"
class Solution:
def __init__(self, dayNumber):
self.dayNumber = dayNumber
self.inputPath = path.format(self.dayNumber)
def part1(self):
pass
def part2(self):
pass
def solve(self):
return ("Day {} Solutions: \n\tPart1: {}\n\tPart2: {}"
.format(self.dayNumber, self.part1(), self.part2()))
day1.py
import fileinput
from solutions.solution import Solution
class Day1(Solution):
def __init__(self):
super().__init__(1)
def part1(self):
return "sol"
def part2(self):
return "sol2"
When you're using the getattr on the imported module, you're getting the class definition. Methods are only callable on class instances, otherwise they throw the error you're seeing:
class A:
def a(self):
pass
A.a() // Will throw "TypeError: a() missing 1 required positional argument: 'self'"
A().a() // OK
Changing the __main__ part this way should solve the issue:
if __name__ == '__main__':
for day in days() :
day_class = getattr(__import__(str("solutions." + day)), day.replace("d", "D"))
day_instance = day_class()
print(day_instance.solve())
For understanding decorators in Python, i created in a class an example. But when i run it i receive an error.
class Operation:
def __init__(self, groupe):
self.__groupe = groupe
#property
def groupe(self):
return self.__groupe
#groupe.setter
def groupe(self, value):
self.__groupe = value
def addition(self, func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
if __name__ == '__main__':
p1 = Operation('Student')
p1.goodbye()
I receive this error :
Traceback (most recent call last):
File "Operation.py", line 1, in
class Operation:
File "Operation.py", line 21, in Operation
#addition
TypeError: addition() missing 1 required positional argument: 'func_goodbye'
You can have a class scoped decorator, however there won't be a self when the decorator is called
a decorator:
#foo
def bar(): ...
is roughly equivalent to
def bar(): ...
bar = foo(bar)
in your particular example, if you remove the self parameter, it should function as you expect:
def addition(func_goodbye):
ln_house = len('house')
ln_school = len('school')
add = ln_house + ln_school
print('The result is :' + str(add))
return func_goodbye
#addition
def goodbye(self):
print('Goodbye people !!')
for good measure, I might del addition after that just to ensure it isn't accidentally called later
(an aside: one unfortunate side-effect of this is many linters and type checkers will consider this "odd" so I've yet to find a way to appease them (for example mypy))
TypeError: _slow_trap_ramp() takes 1 positional argument but 2 were given
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
set_trap_ramp = InstrumentsClass.KeysightB2962A.set_trap_ramp
return set_trap_ramp
def _slow_trap_ramp(self):
slow_trap_ramp = ExperimentsSubClasses.FraunhoferAveraging.slow_trap_ramp
return slow_trap_ramp
The error is straightforward.
ramp = self._slow_trap_ramp(j)
You are calling this method with an argument j, but the method doesn't take an argument (other than self, which is used to pass the object).
Re-define your method to accept an argument if you want to pass it one:
def _slow_trap_ramp(self, j):
It looks like your code extract contains methods of some class, whose full definition is not shown, and you are calling one method from another method (self._slow_trap_ramp(j)). When you call a method, Python automatically passes self before any other arguments. So you need to change def _slow_trap_ramp(self) to def _slow_trap_ramp(self, j).
Update in response to comment
To really help, we would need to see more of the class you are writing, and also some info on the other objects you are calling. But I am going to go out on a limb and guess that your code looks something like this:
InstrumentsClass.py
class KeysightB2962A
def __init__(self):
...
def set_trap_ramp(self):
...
ExperimentsSubClasses.py
class FraunhoferAveraging
def __init__(self):
...
def slow_trap_ramp(self, j):
...
Current version of main.py
import InstrumentsClass, ExperimentsSubClasses
class MyClass
def __init__(self)
...
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
set_trap_ramp = InstrumentsClass.KeysightB2962A.set_trap_ramp
return set_trap_ramp
def _slow_trap_ramp(self):
slow_trap_ramp = ExperimentsSubClasses.FraunhoferAveraging.slow_trap_ramp
return slow_trap_ramp
if __name__ == "__main__":
my_obj = MyClass()
my_obj.demag_chip()
If this is the case, then these are the main problems:
Python passes self and j to MyClass._slow_trap_ramp, but you've only defined it to accept self (noted above),
you are using class methods from KeysightB2962A and FraunhoferAveraging directly instead of instantiating the class and using the instance's methods, and
you are returning references to the methods instead of calling the methods.
You can fix all of these by changing the code to look like this (see embedded comments):
New version of main.py
import InstrumentsClass, ExperimentsSubClasses
class MyClass
def __init__(self)
# create instances of the relevant classes (note parentheses at end)
self.keysight = InstrumentsClass.KeysightB2962A()
self.fraun_averaging = ExperimentsSubClasses.FraunhoferAveraging()
def demag_chip(self):
coil_probe_constant = float(514.5)
field_sweep = [50 * i * (-1)**(i + 1) for i in range(20, 0, -1)] #print as list
for j in field_sweep:
ramp = self._slow_trap_ramp(j)
def _set_trap_ramp(self):
# call instance method (note parentheses at end)
return self.keysight.set_trap_ramp()
def _slow_trap_ramp(self, j): # accept both self and j
# call instance method (note parentheses at end)
return self.fraun_averaging.slow_trap_ramp(j)
if __name__ == "__main__":
my_obj = MyClass()
my_obj.demag_chip()
I using the wx library to build a GUI. I have initialized a panel and intialized some push buttons and have binded a function that will execute when pushed. The function takes a list of arguments, one which is a callback function. What I am trying to do is redefine the callback function during runtime but I am failing to do so.
My attempt so far is:
self.UpdateCurrent = None
self.GetCurrent = None
self.UpdateCellVoltage = None
self.GetCellVoltage = None
self.UpdateCellTemperature = None
self.GetCellTemperature = None
self.battery_control_d = OrderedDict([('Current',[self.UpdateCurrent, self.GetCurrent, None, 1]),
('Cell Voltage',[self.UpdateCellVoltage, self.GetCellVoltage, 0, 24]),
('Cell Temperature',[self.UpdateCellTemperature, self.GetCellTemperature, 0, 24])])
.
.
.
submit_btn_l[-1].Bind(wx.EVT_BUTTON,
lambda evt,
io_name = io_name,
callback_fn = self.battery_control_d[io_name][0],
ctrl_textbox = ctrl_textbox,
dim_combobox = self.dim_combobox_l[-1]:
self._send_control_value(evt,
io_name,
callback_fn,
ctrl_textbox,
dim_combobox))
.
.
.
def init_battery_intf(self):
self.battery_intf = self.simulator_main_panel.battery_intf
self.UpdateCurrent = self.battery_intf.UpdateCurrent
self.GetCurrent = self.battery_intf.GetCurrent
self.UpdateCellVoltage = self.battery_intf.UpdateCellVoltage
self.GetCellVoltage = self.battery_intf.GetCellVoltage
self.UpdateCellTemperature = self.battery_intf.UpdateCellTemperature
self.GetCellTemperature = self.battery_intf.GetCellTemperature
.
.
.
def _send_control_value(self,
evt,
io_name,
callback_fn,
ctrl_textbox,
dim_combobox):
io_value = float(ctrl_textbox.Value)
if ("Temperature" in io_name):
io_value -= self.simulator_main_gui.temperature_unit_converter
callback_fn(io_value, int(dim_combobox.Value))
def update( self,
evt ):
for io_name, io_info in self.battery_control_d.iteritems():
io_value = float(io_info[1](io_info[2]))
self.reading_text_l[self.io_indexer.index(io_name)].SetLabel(" %.4f " % (io_value))
I predefine some update/get objects.
I bind the function to the buttons
During runtime I call init_battery_intf to initialize these objects
The line that errors out is when I try to call the callback function. It seems to be still be set to None.
Traceback (most recent call last):
File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 1185, in updat
self.control_notebook.update(evt)
File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 869, in update
self.battery_control_panel.update(evt)
File "C:\Users\Sam\Desktop\work\simulator\src\simulate.py", line 591, in update
io_value = float(io_info[1](io_info[2]))
TypeError: 'NoneType' object is not callable
I know I could redefine the bind and feed in the values directly, but I wanted to keep my code clean and simple, and I feel like Python has a way to distribute the redefined callback function to all instances of the object.
I'm using Python 2.7.
You have a few options:
A: Have self.UpdateCurrent and the other methods used by self.battery_control_d already initialized. (never initialize to None)
B: when self.UpdateCurrent and/or the others are updated recreate/update self.battery_control_d.
C: Use a name reference and get the value of that attribute when accessed from self.battery_control_d.
The first two are pretty self explanatory but it seems you are interested in option C so I will expand on it:
You can create a class with several property(ies) that retrieve an attribute from your original object when accessed.
class VarReference(object):
def __init__(self, inst, update_name, get_name, value1, value2):
self.inst = inst
self.update_attr_name = update_name
self.getter_attr_name = get_name
self.value1 = value1
self.value2 = value2
#property
def get(self):
return getattr(self.inst, self.getter_attr_name)
#property
def update(self):
return getattr(self.inst, self.update_attr_name)
class Test(object):pass #dummy class for my demo
self = Test()
self.UpdateCurrent = self.GetCurrent = None
ref_obj = VarReference(self,"UpdateCurrent","GetCurrent",None,1)
>>> print(ref_obj.get)
None
>>> self.GetCurrent = lambda:5
>>> ref_obj.get
<function <lambda> at 0x1057d5488>
>>> ref_obj.get()
5
If you are unfamiliar with property basically the function that it decorates is called when the attribute name is accessed on an instance (and therefore retrieving an attribute of the original instance)
so you would in this case write the initialization for self.battery_control_d like this:
self.battery_control_d = OrderedDict([('Current',VarReference(self, "UpdateCurrent", "GetCurrent", None, 1)),
('Cell Voltage',VarReference(self, "UpdateCellVoltage", "GetCellVoltage", 0, 24)),
('Cell Temperature',VarReference(self, "UpdateCellTemperature", "GetCellTemperature", 0, 24))
])
then self.battery_control_d["current"].get would be the result of getattr(self,"GetCurrent") which is equivalent to self.GetCurrent dynamically.
If you really want to use VALUE[0] and VALUE[1] instead of VALUE.update and VALUE.get then you can just override __getitem__ of the class as well, although I'd highly recommend switching to more verbose solutions:
class VarReference(object):
...
def __getitem__(self,item):
if item==0:
return self.update
elif item == 1:
return self.get
elif item ==2:
return self.value1
elif item == 3:
return self.value2
else:
raise IndexError("Can only get indices from 0 to 3")
What is the error below? Also, is there a better way to implement the following classes?
#!/usr/bin/python
class Datacenters:
def __init__(self,name,location,cpu,mem):
self.name=name
self.location=location
self.cpu=cpu
self.mem=mem
def getparam(self):
return self.name,self.location ,self.cpu,self.mem
def getname(self):
return self.name
class WS(Datacenters):
def __init__(self,name,location,cpu,mem,obj):
#datacentername = Datacenters.__init__(self) #To which data center it is associated
self.dcname =obj.name #To which data center it is associated
Datacenters.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
self.name,self.location ,self.cpu,self.mem = obj.getparam()
print self.dcname
#return self.name,self.location ,self.cpu,self.mem,obj.name
def getwsname(self):
return self.name
class Pcs(WS):
def __init__(self,name,location,cpu,mem,obj):
self.wsname = obj.getwsname() #To which WS it is associated
WS.__init__(obj,name,location,cpu,mem)
def getparam(self,obj):
print obj.getparam()
print self.wsname
a = Datacenters("dc1","Bl1",20,30)
print a.getparam()
b = WS("WS1","Bl1",21,31,a)
print b.getparam(a)
c = Pcs("PC1","Bl1",20,30,b)
#print c.getparam(b)
output:
Press ENTER or type command to continue
('dc1', 'Bl1', 20, 30)
dc1
None
Traceback (most recent call last):
File "class1.py", line 45, in <module>
c = Pcs("PC1","Bl1",20,30,b)
File "class1.py", line 34, in __init__
WS.__init__(obj,name,location,cpu,mem)
TypeError: __init__() takes exactly 6 arguments (5 given)
The error is that you pass in five arguments, but the __init__ needs six. Count them:
def __init__(self,name,location,cpu,mem,obj):
Six arguments. You call it like so:
WS.__init__(obj,name,location,cpu,mem)
Five arguments. The first one, self is missing. What you should ask yourself is why you don't have to pass in six arguments all the time.
And that is because self is passed in automatically when you call the method on an instance. However, in this case you don't call it on an instance, you call it directly on the class. There is of course no need to do so in this case, the correct syntax is:
WS(obj,name,location,cpu,mem)
As you indeed above note works further up.