I want the user to be able to initiate a class by passing an argument to it, and if he doesn't pass it then it should be automatically created by the class. How is that usually done in Python? Example:
class MyClass(object):
def __init__(self, argument):
self.argm = argument
# logic here: if user does not pass argument
# run some function or do something
def create_argm(self):
self.argm = 'some_value'
object_example = MyClass()
print(object_example.argm) # will print 'some_value'
object_example = MyClass('some_other_value')
print(object_example) # will print 'some_other_value'
Edit : self.argm will be a python-docx Object so i'm unable to do def __init__(self, argument = Document() or am i?
if you cant create the value in the function definition, you can use a value that indicates nothing, luckily python has None so you can do something like:
class MyClass(object):
def __init__(self, argument=None):
if argument is None:
self.argm = self.create_argm()
else:
self.argm = argument
def create_argm(self):
return 'some_value'
if None Doesn't fit because you want that to be a valid value for argument without assuming it was left out you can always create a dummy value:
class MyNone:
pass
class MyClass(object):
def __init__(self, argument=MyNone):
if argument is MyNone:
self.argm = self.create_argm()
else:
self.argm = argument
def create_argm(self):
return 'some_value'
This is usually done with a default value assigned to a key word argument:
class MyClass(object):
def __init__(self, argument='default value'):
self.argm = argument
You have to pay special attention if you want this default value to be a mutable object; this may lead to unwanted behavior, as the object will be created only once, then mutated.
Related
I am trying to write a function taking a string as an argument and using this argument as a class object.
Note that my explanantion might be strangely formulated sice I could not find an answer online. The MWE below should clarify what I mean, the problematic line is indicated.
Edit: in the MWE, "print" is an example. I need to be able to call the object to update it, print it or, in the case of a list, append to it. I need access to the object itself, not the value of the object.
MWE
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Define function
def myFunction (parameter):
print(myObject.parameter)##### This line is currently not possible.
# Use class
myObject = myClass()
# Use function
myFunction("one")
I am not trying to append a new object to the class, only to call an existing object.
Is this even possible?
Looks like you need the built-in function called getattr
my_object = myClass()
def my_function(parameter):
print(getattr(my_object, parameter, None))
also this is not the best practice to call objects from outer scope like that. i'd suggest to use dict magic methods:
class MyClass:
def __init__(self):
self.one = "Test"
self.two = "Plop"
def __getitem__(self, parameter):
return getattr(self, parameter, None)
def __setitem__(self, parameter, value):
return setattr(self, parameter, value)
my_obj = MyClass()
parameter = "x"
print(my_obj[parameter])
my_obj[parameter] = "test"
print(my_obj.x)
You need to use getarttr():
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Use class
myObject = myClass()
# Define function
def myFunction(parameter):
print(getattr(myObject, parameter))##### This line is currently possible.
# Use function
myFunction("one")
class Foo:
def __init__(self, id: int, username: str):
self.id = id
self.username = username
dict = {'id':1,'username':'bar', 'extra':0}
x = Foo(**dict) # Foo.__init__() got an unexpected keyword argument 'extra'
I'm working with some web services that sometimes have extra data in the response that I don't care about. The simplified example above illustrates the problem. Is there a way to use a dictionary to initialize an object, without manually entering each desired key as an argument?
Rather than trying to somehow ignore extraneous arguments, why not take a more flexible approach by accepting all parameters regardless of the order in which they are presented to the class constructor.
Then declare properties (getters & setters) to subsequently access the values.
For example:
class Foo:
def __init__(self, **kwargs):
self.kwargs = kwargs
#property
def username(self):
return self.kwargs.get('username')
#username.setter
def username(self, value):
self.kwargs['username'] = value
#property
def ident(self):
return self.kwargs.get('ident')
#ident.setter
def ident(self, value):
self.kwargs['ident'] = value
def __repr__(self):
return ', '.join(f'{k}={v}' for k, v in self.kwargs.items())
f = Foo(ident=123)
print(f.ident)
print(f.username)
f.username = 'Lancelot'
print(f.username)
print(f)
Output:
123
None
Lancelot
ident=123, username=Lancelot
The only disadvantage to this that I can think of (there may be others) is that you would not be able to distinguish between values that were not passed to the constructor and those that had a value of None. You'd need to make your getters more elaborate to handle that
I have a simple class. I want to set the periodicity property using a private attribute which is tested before being used to set the public attribute. I am passing self around the class module, when I run the test code the function seems to expect 2 arguments. I thought it should ignore self and ask for the one freq parameter. I am trying to be "pythonic" and use #property with .setter. Do I need to change the property call? If I remove self from set_periodicity it says it does not recognize self.
class ModelSetUp:
def __init__(self):
self.periodicity= None
#property
def set_periodicity(self,freq):
self.periodicity = self._periodicity
#set_periodicity.setter
def set_periodicity(self,freq):
if freq in ("Q","S","A"):
self._periodicity = freq
else:
raise ValueError("Frequency Must Be Q, S or A")
if __name__=="__main__":
mod = ModelSetUp()
mod.set_periodicity("Q")
Properties don't take any arguments, nor are they callable. Try this:
class ModelSetUp:
def __init__(self):
self._periodicity = None
#property
def periodicity(self):
return self._periodicity
#periodicity.setter
def periodicity(self, freq):
if freq in ("Q","S","A"):
self._periodicity = freq
else:
raise ValueError("Frequency Must Be Q, S or A")
if __name__=="__main__":
mod = ModelSetUp()
mod.periodicity = "Q"
I have a class that I want to take an arbitrary method at initialization to use for string parsing depending on the context.
Using a method defined outside of a class as discussed here: Python define method outside of class definition?
def my_string_method(self):
return self.var.strip()
class My_Class():
def __init__(self, string_method):
self.var = ' foo '
self.string_method = string_method
def use_string_method(self):
return self.string_method()
instance = My_Class(string_method=my_string_method)
print instance.use_string_method()
I get the error "TypeError: use_string_method() takes exactly 1 argument (0 given)".
Shouldn't the self argument be passed implicitly to use_string_method?
Is there a way to define the function such that this occurs, or do I need to explicitly pass the self argument to methods defined outside of the class as such:
class My_Class():
def __init__(self, string_method):
self.var = ' foo '
self.string_method = string_method
def use_string_method(self):
return self.string_method(self)
You will have to wrap the passed in function in "MethodType".
From within your init:
self.string_method = types.MethodType(string_method, self)
This binds the method to the class and allows it to receive the implicit self parameter. Make sure you import types at the top of your script.
1st file:
class Profile(object):
def __init__(self, name, 1st_arg=gst(), 2nd_arg=1, 3rd_arg=AB.parallel):
self.name = name
self.gain = 1st_arg(i, o, p)
self.channel = 2nd_arg
self.mode = 3rd_arg
2nd file:
class A:
some_function():
1st_arg = gst(i, o, p) # class gst constructor
result = Profile(Name, 1st_arg, 2nd_arg=1, 3rd_arg=Phase) # profile class constructor
I have above code, but i want to change "1st_arg" to named argument from keyword argument.
Here 2nd_arg and 3rd_arg arguments clearly specify to whom their values are being assigned, but not the same in 1st_arg.
I want this change so that if some 3rd party saw my code then he would understand it easily.
If you want to convert a positional argument to a keyword argument (and it's the last keyword argument), just specify its name. For example, if you have a call of the following form:
f(val1, val2, arg3=val3, arg4=val4)
and you want to provide val2 as a keyword argument, just call it like
f(val1, arg2=val2, arg3=val3, arg4=val4)
If the argument you want to convert isn't the last positional argument, you'll have to convert all following positional arguments to keyword arguments, too.
Easy, just change the argument from a keyword argument to a positional argument:
class Profile(object):
def __init__(self, name, gst, 2nd_arg=1, 3rd_arg=AB.parallel):
self.name = name
self.gain = gst(i, o, p)
self.channel = 2nd_arg
self.mode = 3rd_arg
You had a bigger problem, though. Calling a function in a method signature in Python only calls that function once, at compile-time. So, if you were noticing some unusual behavior related to gst() being in the method signature, that's why. If you pass a function reference as an argument, it can be called later. Don't call the gst() in the method signature itself, just pass it in as gst.
Edit: I think this is what you're after
class Profile(object):
def __init__(self, name, 1st_arg=gst(sane, default, args), 2nd_arg=1, 3rd_arg=AB.parallel):
self.name = name
self.gain = 1st_arg
self.channel = 2nd_arg
self.mode = 3rd_arg
value = gst(i, o, p)
result = Profile(Name, 1st_arg=value, 2nd_arg=1, 3rd_arg=Phase)