Default parameter in python with objects - python

I know I can define default parameters in python, but can I do so with objects?
For example, I'd like to work with a p.expect object:
def exitDevice(ip, m='', sendExit=True):
if sendExit:
m.send('exit')
print "left device", ip
Is that the correct way to handle an object passed in as a default argument in Python? If not, how does one do so? Or if this is correct is there a better way to do so?

It's a bit tricky, since the default value has to be defined at the time your code is parsed, but you can always do something like this:
def exitDevice(ip,m=None,sendExit=True):
if m is None: m = getDefaultValueForM()
if sendExit: m.send ( 'exit' )

Related

How to set argument of an object?

so I want to know if there is a solution to make an argument which is not organised when I create an object.
class Joueur:
nbrJoueur=0
def __init__(self,c_pseudo,c_pv=25,c_sttat=0):
self.pseudo=c_pseudo
self.pv=c_pv
self.sttat=c_sttat
Joueur.nbrJoueur+=1
j1=Joueur("adel",250,0)
j2=Joueur("salah",c_sttat=10)
So like in j2 I had to make c_sttat=10 to avoid that it's the the c_pv which take the value 10.
So I want to avoid that problem when I have a lot of arguments how could I do that?
I think this may be what you want:
def __init__(self,c_pseudo, *, c_pv=25,c_sttat=0):
When you put * in the parameter list, all the arguments after that position must be given with keywords. So if you try to write
j2 = Joueur("joseph", 10)
you'll get an error because you didn't name the second argument. This forces you to indicate whether it's c_pv or c_sttat

Python ast - getting function parameters and processing them

I'm trying to use the ast module in Python to parse input code, but am struggling with a lot of the syntax of how to do so. For instance, I have the following code as a testing environment:
import ast
class NodeVisitor(ast.NodeVisitor):
def visit_Call(self, node):
for each in node.args:
print(ast.literal_eval(each))
self.generic_visit(node)
line = "circuit = QubitCircuit(3, True)"
tree = ast.parse(line)
print("VISITOR")
visitor = NodeVisitor()
visitor.visit(tree)
Output:
VISITOR
3
True
In this instance, and please correct me if I'm wrong, the visit_Call will be used if it's a function call? So I can get each argument, however there's no guarantee it will work like this as there are different arguments available to be provided. I understand that node.args is providing my arguments, but I'm not sure how to do things with them?
I guess what I'm asking is how do I check what the arguments are and do different things with them? I'd like to check, perhaps, that the first argument is an Int, and if so, run processInt(parameter) as an example.
The value each in your loop in the method will be assigned to the AST node for each of the arguments in each function call you visit. There are lots of different types of AST nodes, so by checking which kind you have, you may be able to learn things about the argument being passed in.
Note however that the AST is about syntax, not values. So if the function call was foo(bar), it's just going to tell you that the argument is a variable named bar, not what the value of that variable is (which it does not know). If the function call was foo(bar(baz)), it's going to show you that the argument is another function call. If you only need to handle calls with literals as their arguments, then you're probably going to be OK, you'll just look instances of AST.Num and similar.
If you want to check if the first argument is a number and process it if it is, you can do something like:
def visit_Call(self, node):
first_arg = node.args[0]
if isinstance(first_arg, ast.Num):
processInt(first_arg.n)
else:
pass # Do you want to do something on a bad argument? Raise an exception maybe?

How to avoid repetition in a ternary operator assignment?

When fetching a number of config values from os.environ, it's nice to have defaults in the python code to easily allow the application to start in a number of contexts.
A typical django settings.py has a number of
SOME_SETTING = os.environ.get('SOME_SETTING')
lines.
To provide sensible defaults we opted for
SOME_SETTING = os.environ.get('SOME_SETTING') or "theValue"
However, this is error prone because calling the application with
SOME_SETTING=""
manage.py
will lead SOME_SETTING to be set to theValue instead of the explicitly defined ""
Is there a way to assign values in python using the ternary a = b if b else d without repeating b or assigning it to a shorthand variable before?
this becomes obvious if we look at
SOME_VERY_LONG_VAR_NAME = os.environ.get('SOME_VERY_LONG_VAR_NAME') if os.environ.get('SOME_VERY_LONG_VAR_NAME') else 'meh'
It would be much nicer to be able to do something like
SOME_VERY_LONG_VAR_NAME = if os.environ.get('SOME_VERY_LONG_VAR_NAME') else 'meh'
Just like Python's built-in mapping class dict, os.environ.get has a second argument, and it seems like you want it:
SOME_SETTING = os.environ.get('SOME_SETTING', "theValue")
This is the same as
try:
SOME_SETTING = os.environ['SOME_SETTING']
except KeyError:
SOME_SETTING = "theValue"
If you read dict.get()'s doc, you'll find out the method's signature is get(self, key, default=None). The default argument is what gets returned if the key is not found in the dict (and default to a sensible None). So you can use this second argument instead of doing an erroneous boolean test:
SOME_SETTING = os.environ.get('SOME_SETTING', "theValue")

Python: Using string stored in variable to create attribute to class

I am trying to follow syntax of the pyparticleio.ParticleCloud package. Using the following command, my code works correctly "particle_cloud.boron1.led('on')" (hardcoded values)
I want to pass portions of the command, "boron1" and "on" as variable. I'm trying to figure out how to use those variables to act in the same way as if i'd hardcoded the values.
My python level is very beginner.
command_list['boron1','on']
device = command_list[0]
function_1 = command_list[1]
access_token = "ak3bidl3xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
particle_cloud = ParticleCloud(username_or_access_token=access_token)
#particle_cloud.boron1.led('on') #hardcoded example that works
particle_cloud.device.led(function_1) #what i would like to work
If you set device to the actual object, you can call methods on the object. Example:
device = particle_cloud.boron1 # Or whatever you like
arg = 'on' # Also make this whatever you like
device.led(arg) # Same as: particle_cloud.boron1.led('on')
Python has a built in function called exec
It allows you to take a string, and have Python execute it as code.
A basic example based on the code you provided would look like this:
command_list['boron1','on']
device = command_list[0]
function_1 = command_list[1]
exec('particle_cloud.' + device + '.led("' + function_1 + '")')
This is a bit ugly, but there are different ways to compose strings in Python such as using join or format so depending on your real code you may be able to build something nice.
Just be careful not to pass raw user input to exec!
I can cause all kinds of trouble from errors to security issues.
I believe you could use getattr() (in Python3: https://docs.python.org/3/library/functions.html#getattr ) :
pcdevice = getattr(particle_cloud, device)
pcdevice.led(function_1)
(BTW, I woudln't name the string 'on' with the label 'function_1' as the variable name implies that this option is a function when it is a string. Also, the above may now work depending on the properties of your library object ParticleCloud.)

How to pass a parameter as a default?

I want to use the default of a parameter, but include its name in the call. I thought that setting the parameter to None would do that, but it doesn't.
For example:
def a(num=3):
print(num)
a(num=None) #returns "None", not "3" like I want it to.
How can I use the default of a named parameter while including it in the call? (Is it even possible?)
Just to explain why I would want to do something like this (since maybe it's a problem in my overall coding style):
I often times have code like this
def add(num, numToAdd=1):
return num+numToAdd
def addTwice(num, numToAdd=None):
for i in range(2):
num=add(num, numToAdd=numToAdd)
return num
addTwice(3) #throws an error instead of returning 5
What I want is for addTwice's numToAdd to always use the default of add's numToAdd, no matter what it is.
The reason: maybe later in the code I realize that it's better to add 2 as the default when executing add than it is to add 1.
So I change it to
def add(num, numToAdd=2):
return num+numToAdd
But, this won't help anything unless I can always specify in addTwice to use the default if it receives a default.
So, that's the rationale.
In other words: I'm having a function (the first function) call another function (the second function), and if the first function has to use a default value, I want it to default to being the default value on the second function. That way, I only have to change the default value on the second function (not every single function that calls it as well) in order to change the default functionality.
There's no built-in support to explicitly use the default value of a parameter. If you don't want to leave the parameter out at the call site, you'd have to retrieve the default value very manually:
import inspect
a(num=inspect.signature(a).parameters['num'].default)
which wouldn't be worth it in most cases.
def a(num=None):
if num is None:
num = 3
print(num)
a(num=None) # prints 3
a() # prints 3
... I guess ... maybe
alternatively to explain default params
def a(num=3):
print(num)
a(num=None) # prints None
a() # prints 3
No, you can't: that's a contradiction in terms. The default value is used if and only if you do not supply a value in the arguments list. If you supply a value, then the default cannot be used within the routine.
There is a great answer on how to do this (if you decide that the default-getting functionality I asked for is really what you want). But, I just wanted to point out that in practice I believe what I was trying to achieve is normally done with global variables.
That is, the usual way to do what I wanted to do is:
DEFAULT_NUM_TO_ADD = 1
def add(num, numToAdd=DEFAULT_NUM_TO_ADD):
return num+numToAdd
def addTwice(num, numToAdd=DEFAULT_NUM_TO_ADD):
for i in range(2):
num=add(num, numToAdd=numToAdd)
return num
addTwice(3) # returns 5
This allows me to quickly change the default, and the same default is used for both functions. It's explicit and very clear; it's pythonic.

Categories

Resources