Is it possible in python to call dot-syntax-function based on condition. Simple example to turn:
if condition:
foo().bar().baz()
lots_of_code()
else:
foo().baz()
lots_of_code()
def lots_of_code():
# lots of code
into:
foo().(if condition: bar()).baz()
# lots of code only once
No, it is not possible.
The syntax for attribute reference is
attributeref ::= primary "." identifier
Quoting the documentation,
An attribute reference is a primary followed by a period and a name
name must be a regular Python identifier and identifiers can't contain special characters like (.
However, you can use a simple conditional expression to select primary:
(foo().bar() if condition else foo()).baz()
It's equivalent to
if condition:
primary = foo().bar()
else:
primary = foo()
primary.baz()
Note that in this case we have to use parentheses, because attribute reference has higher precedence than conditional expression.
Since foo() is called in either case, start by doing so unconditionally. Save that object to f, with the intention of calling f.baz(). Before that, though, check your condition to see if f should really be the result of foo().bar().
f = foo()
if condition:
f = f.bar()
f.baz()
Related
I understand that you can use "pass" in a user defined function, say, when you do not want to put anything in it at the moment. Where else can I possibly use this keyword? When assigning it to a variable for example, I get an error: my_item = pass Why is this happening and where else can I use this keyword at?
pass is, by itself, an entire statement, and can be used anywhere a statement is expected, but almost always are found in the body of a compound statement.
def foo():
pass
if True:
pass
for x in y:
pass
class Bar:
pass
with foo as bar:
pass
etc.
It is typically used where some statement is needed to fill an otherwise empty code block. Note that since any expression can be used as a statement (a so-called expression statement), you can sometimes use a doc string in place of a pass statement:
class FooError(ValueError):
'''A very specific kind of ValueError'''
instead of
# Legal, but unnecessary
class FooError(ValueError):
'''A very specific kind of ValueError'''
pass
You can only place an expression, not a statement, on the right-hand side of an assignment statement, which is why my_item = pass is a syntax error.
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")
In python, one can attribute some values to some of the keywords that are already predefined in python, unlike other languages. Why?
This is not all, some.
> range = 5
> range
> 5
But for
> def = 5
File "<stdin>", line 1
def = 5
^
SyntaxError: invalid syntax
One possible hypothesis is - Lazy coders with unique parsing rules.
For those new to python, yeah, this actually works, for keywords like True, False, range, len, so on.
I wrote a compiler for python in college and, if I remember correctly, the keywords list did not have them.
While range is nothing but a built-in function, def is a keyword. (Most IDEs should indicate the difference with appropriate colors.)
Functions - whether built-in or not - can be redefined. And they don't have to remain functions, but can become integers like range in your example. But you can never redefine keywords.
If you wish, you can print the list of all Python keywords with the following lines of code (borrowed from here):
import keyword
for keyword in keyword.kwlist:
print keyword
Output:
and
as
assert
break
class
continue
def
del
elif
else
except
exec
finally
for
from
global
if
import
in
is
lambda
not
or
pass
print
raise
return
try
while
with
yield
And for Python 3 (notice the absence of print):
False
None
True
and
as
assert
break
class
continue
def
del
elif
else
except
finally
for
from
global
if
import
in
is
lambda
nonlocal
not
or
pass
raise
return
try
while
with
yield
In contrast, the built-in functions can be found here: https://docs.python.org/2/library/functions.html
The keyword 'range' is a function, you can create some other vars as well as sum, max...
In the other hand, keyword 'def' expects a defined structure in order to create a function.
def <functionName>(args):
You are confused between keywords and built-in functions. def is a keyword, but range and len are simply built-in functions. Any function can always be overridden, but a keyword cannot.
The full list of keywords can be found in keywords.kwlist.
At a certain point in my project, I need to query a SQLAlchemy object for columns that are NOT NULL. In my code, I do:
session.query(MyModel).filter(MyModel.my_column != None).all()
...and it works great. Problem is, whenever I run pep8 or one of the other linters on the file, it raises an error E711: Comparison to None should be if cond is not None:. I agree with the spirit of this guideline, and as such I don't want to silence the warning just because of one little line.
Is there another way to write this? Preferably one where we don't have to dig into the func module?
PEP8 isn't meant to be followed to the letter.
You're recommended to use is None instead of == None because is cannot be overloaded (unlike ==):
>>> class Bad(object):
... def __eq__(self, other):
... return True
...
>>> instance = Bad()
>>> instance == None
True
>>> instance is None
False
In your case you want to use the overloaded == operator, so the warning is incorrect.
There are three ways of making the warning go away:
You can disable that particular warning for that single line:
For Flake8/PyFlakes:
session.query(MyModel).filter(MyModel.my_column != None).all() # noqa: E711
For Pylint:
session.query(MyModel).filter(MyModel.my_column != None).all() # pylint: disable=singleton-comparison
You can avoid using the equality operator by directly calling the class's __eq__ (for ==) and __ne__ (for !=) methods:
session.query(MyModel).filter(MyModel.my_column.__ne__(None)).all()
You can use .is_ and .isnot:
session.query(MyModel).filter(MyModel.my_column.isnot(None)).all()
Note that .is_ and .isnot are not the same as == and !=. MyModel.my_column != x can mean both IS NOT NULL and != x depending on the value of x and your database, so solutions 1 and 2 are probably better unless you really don't like using __-methods and know the type of the right-hand-side of your expression.
I've heard that python functions are objects, similar to lists or dictionaries, etc. However, what would be a similar way of performing this type of action with a function?
# Assigning empty list to 'a'
a = list()
# Assigning empty function to 'a'
a = lambda: pass
# ???
How would you do this? Further, is it necessary or proper?
Here is the sense in which I would like to use it for better context:
I have a QListWidget for selecting items which are associated with keys in a dictionary. The values in this dictionary are also dictionaries, which hold certain properties of the items, which I can add. These certain properties are stored as keys, and the values in them are initialized or updated by calling different functions. So, I'm storing a variable in the window which gets updated when a button is pressed to tell this script which property to update.
As you can see, I would like to store the function to map to the data using the correct function based on the situation.
# Get selection from the list
name = selected_item
# Initialize an empty function
f = lambda: pass
# Use property that is being added now, which was updated by the specific button that was pushed
property_list = items[name][self.property_currently_being_added]
if self.property_currently_being_added == "prop1":
f = make_property1()
elif self.property_currently_being_added == "prop2":
f = make_property2()
elif self.property_currently_being_added == "prop3":
f = make_property3()
elif self.property_currently_being_added == "prop4":
f = make_property4()
# map the certain function to the data which was retrieved earlier
added_property = map(f, data)
property_list.append(added_property)
First, the reason this doesn't work:
a = lamdba: pass
… is that lambda only allows an expression, and defines a function that returns the value of the expression. Since pass is a statement, not an expression, this is illegal.
However, this works just fine:
a = lambda: None
In Python, a function that falls off the end without a return statement always returns None. So, these are equivalent:
def a(): return None
def a(): pass
However, I don't see why you want to write this as a lambda and an assignment anyway; the def is shorter, and more readable, and gives you an introspectable function object with a nice name (a instead of <lambda>), and so on. The only reasons to ever use lambda are when you don't want to give the function a name, or when you need to define the function inside an expression. Obviously neither of those are true, because you use the lambda directly inside an assignment statement. So, just use def.
Meanwhile, this is in a sense an "empty function", or at least as empty as possible (as you can see by, e.g., calling dis.dis(a), it still takes two bytecodes to do nothing but fall off the end and return None), but it's not useful for your case. You don't want an "empty function". If you try passing your a to map, you're just going to get a TypeError, because you're trying to call a function of no arguments with one argument. (Because that's what map does.)
What you might want is an identity function, which just returns its argument as-is. Like this:
def a(x): return x
But I'm not sure that's what you want. Did you want to append data as-is in that case? Or did you want to do something different, like return early, or raise an exception, or not append anything, or …?
Finally, I don't see why you want a function at all. Why not just not call map if you have nothing to map? You have a perfectly good else clause that already catches that case (especially handy if what you want to do is return early or raise…). Or, if you prefer, you can start with f = None, and then use an if f: do decide whether to map or not. Or, if you really want:
added_property = [f(element) if f else element for element in data]
… or …
added_property = map(f, data) if f else data
As one last note, instead of a long if/elif chain that repeats the same thing over and over again, you might want a dict:
propfuncs = {'prop1': make_property1(),
'prop2': make_property2(),
'prop3': make_property3(),
'prop4': make_property4()}
Then, all that cruft turns into these two lines:
f = propfuncs.get(self.property_currently_being_added)
added_property = map(f, data) if f else data
Or course an even better design might be to replace all those make_propertyN functions with a single function that you call as make_property(1) or make_property('prop1')… but without seeing what they actually do, I can't be sure of that.
For completeness and since the title is "empty function object in python", more general case is an empty function object that takes any number of parameters, so you can use it in any callback. It's this one:
callback = lambda *_, **__: None
Explanation is here: http://echochamber.me/viewtopic.php?t=64825
I am surprised to learn that you can even do...
def a(): "This is a test"
a()
this feels so much like you're looking for a Nothing functor, I am guessing that if you had knowledge of Monads you wouldn't even need an empty function , as inspiration PyMonad has a nice Nothing implementation, I usually like to create my own, but it's a good starting point.