In JavaScript, if I'm not sure whether every element of the chain exists/is not undefined, I can do foo?.bar, and if bar does not exist on foo, the interpreter will silently short circuit it and not throw an error.
Is there anything similar in Python? For now, I've been doing it like this:
if foo and foo.bar and foo.bar.baz:
# do something
My intuition tells me that this isn't the best way to check whether every element of the chain exists. Is there a more elegant/Pythonic way to do this?
If it's a dictionary you can use get(keyname, value)
{'foo': {'bar': 'baz'}}.get('foo', {}).get('bar')
Most pythonic way is:
try:
# do something
...
except (NameError, AttributeError) as e:
# do something else
...
You can use getattr:
getattr(getattr(foo, 'bar', None), 'baz', None)
You can use the Glom.
from glom import glom
target = {'a': {'b': {'c': 'd'}}}
glom(target, 'a.b.c', default=None) # returns 'd'
https://github.com/mahmoud/glom
I like modern languages like Kotlin which allow this:
foo?.bar?.baz
Recently I had fun trying to implement something similar in python:
https://gist.github.com/karbachinsky/cc5164b77b09170edce7e67e57f1636c
Unfortunately, the question mark is not a valid symbol in attribute names in python, thus I used a similar mark from Unicode :)
Combining a few things I see here.
from functools import reduce
def optional_chain(obj, keys):
try:
return reduce(getattr, keys.split('.'), obj)
except AttributeError:
return None
optional_chain(foo, 'bar.baz')
Or instead extend getattr so you can also use it as a drop-in replacement for getattr
from functools import reduce
def rgetattr(obj, attr, *args):
def _getattr(obj, attr):
return getattr(obj, attr, *args)
return reduce(_getattr, attr.split('.'), obj)
With rgetattr it can still raise an AttributeError if the path does not exist, and you can specify your own default instead of None.
Combining some of the other answers into a function gives us something that's easily readable and something that can be used with objects and dictionaries.
def optional_chain(root, *keys):
result = root
for k in keys:
if isinstance(result, dict):
result = result.get(k, None)
else:
result = getattr(result, k, None)
if result is None:
break
return result
Using this function you'd just add the keys/attributes after the first argument.
obj = {'a': {'b': {'c': {'d': 1}}}}
print(optional_chain(obj, 'a', 'b'), optional_chain(obj, 'a', 'z'))
Gives us:
{'c': {'d': 1}} None
Classes can override __getattr__ to return a default value for missing attributes:
class Example:
def __getattr__(self, attr): # only called when missing
return None
Testing it:
>>> ex = Example()
>>> ex.attr = 1
>>> ex.attr
1
>>> ex.missing # evaluates to `None
>>>
However, this will not allow for chaining:
>>> ex.missing.missing
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'missing'
Nor will it deal with attempts to call methods that are absent:
>>> ex.impossible()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
To fix this, we can make a proxy object:
class GetAnything:
def __getattr__(self, attr):
return self
def __call__(self, *args, **kwargs): # also allow calls to work
return self
def __repr__(self):
return '<Missing value>'
# Reassign the name to avoid making more instances
GetAnything = GetAnything()
And return that instead of None:
class Example:
def __getattr__(self, attr): # only called when missing
return GetAnything
Now it chains as desired:
>>> Example().missing_attribute.missing_method().whatever
<Missing value>
Here's some syntactic sugar to make chaining with getattr look more like the fluent interfaces of other languages. It's definitely not "Pythonic", but it allows for something simpler to write.
The idea is to abuse the # operator added in Python 3.5 (to support matrix multiplication in Numpy). We define a class r such that its instances, when matrix-multiplied on the right of another object, invoke getattr. (The combination #r, of course, is read "attr".)
class r:
def __init__(self, name, value=None):
self._name = name
self._value = value
def __rmatmul__(self, obj):
return getattr(obj, self._name, self._value)
Now we can chain attribute accesses easily, without having to modify any other classes (and of course it works on built-in types):
>>> 'foo'#r('bar')#r('baz') # None
>>>
However, the order of operations is inconvenient with method calls:
>>> 'foo bar'#r('split')()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'r' object is not callable
>>> ('foo bar'#r('split'))()
['foo', 'bar']
Python 3.10 introduced the match statement in PEP-634, with the tutorial in PEP-636 being a nice reference.
This statement allow these sorts of "chained" operations to be performed, but note that they are statements and not expressions.
For example, OP could instead do:
match foo:
case object(bar=object(baz=baz)) if baz:
# do something with baz
The reason for needing object is that everything is a subtype of it and hence it always succeeds. It then goes on to check that the attribute exists, which might fail. Exceptions wouldn't be thrown if the attribute didn't exist, just the case wouldn't match and it would move onto the next one (which in this case doesn't exist, so nothing would be done).
A more realistic example would check something more specific, e.g.:
from collections import namedtuple
Foo = namedtuple('Foo', ['bar'])
Bar = namedtuple('Bar', ['baz'])
def fn(x):
match x:
case Foo(bar=Bar(baz=baz)):
return baz
print(fn(Foo(bar=Bar(baz='the value'))))
print(fn(None))
print(fn(1))
which would output:
the value
None
None
If instead you wanted to destructure into dictionaries, you might use something like:
foo = {'bar': {'baz': 'the value'}}
match foo:
case {'bar': {'baz': baz}}:
print(baz)
Related
Suppose I have a python object x and a string s, how do I set the attribute s on x? So:
>>> x = SomeObject()
>>> attr = 'myAttr'
>>> # magic goes here
>>> x.myAttr
'magic'
What's the magic? The goal of this, incidentally, is to cache calls to x.__getattr__().
setattr(x, attr, 'magic')
For help on it:
>>> help(setattr)
Help on built-in function setattr in module __builtin__:
setattr(...)
setattr(object, name, value)
Set a named attribute on an object; setattr(x, 'y', v) is equivalent to
``x.y = v''.
However, you should note that you can't do that to a "pure" instance of object. But it is likely you have a simple subclass of object where it will work fine. I would strongly urge the O.P. to never make instances of object like that.
Usually, we define classes for this.
class XClass( object ):
def __init__( self ):
self.myAttr= None
x= XClass()
x.myAttr= 'magic'
x.myAttr
However, you can, to an extent, do this with the setattr and getattr built-in functions. However, they don't work on instances of object directly.
>>> a= object()
>>> setattr( a, 'hi', 'mom' )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'hi'
They do, however, work on all kinds of simple classes.
class YClass( object ):
pass
y= YClass()
setattr( y, 'myAttr', 'magic' )
y.myAttr
let x be an object then you can do it two ways
x.attr_name = s
setattr(x, 'attr_name', s)
Also works fine within a class:
def update_property(self, property, value):
setattr(self, property, value)
If you want a filename from an argument:
import sys
filename = sys.argv[1]
file = open(filename, 'r')
contents = file.read()
If you want an argument to show on your terminal (using print()):
import sys
arg = sys.argv[1]
arg1config = print(arg1config)
Suppose I have a python object x and a string s, how do I set the attribute s on x? So:
>>> x = SomeObject()
>>> attr = 'myAttr'
>>> # magic goes here
>>> x.myAttr
'magic'
What's the magic? The goal of this, incidentally, is to cache calls to x.__getattr__().
setattr(x, attr, 'magic')
For help on it:
>>> help(setattr)
Help on built-in function setattr in module __builtin__:
setattr(...)
setattr(object, name, value)
Set a named attribute on an object; setattr(x, 'y', v) is equivalent to
``x.y = v''.
However, you should note that you can't do that to a "pure" instance of object. But it is likely you have a simple subclass of object where it will work fine. I would strongly urge the O.P. to never make instances of object like that.
Usually, we define classes for this.
class XClass( object ):
def __init__( self ):
self.myAttr= None
x= XClass()
x.myAttr= 'magic'
x.myAttr
However, you can, to an extent, do this with the setattr and getattr built-in functions. However, they don't work on instances of object directly.
>>> a= object()
>>> setattr( a, 'hi', 'mom' )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'hi'
They do, however, work on all kinds of simple classes.
class YClass( object ):
pass
y= YClass()
setattr( y, 'myAttr', 'magic' )
y.myAttr
let x be an object then you can do it two ways
x.attr_name = s
setattr(x, 'attr_name', s)
Also works fine within a class:
def update_property(self, property, value):
setattr(self, property, value)
If you want a filename from an argument:
import sys
filename = sys.argv[1]
file = open(filename, 'r')
contents = file.read()
If you want an argument to show on your terminal (using print()):
import sys
arg = sys.argv[1]
arg1config = print(arg1config)
Is there a class in Python 2.7 that behaves like:
x = AttrDict(foo=1, bar=2)
x.foo -> 1
x.bar -> 2
for arbitrary attributes / constructor keywords?
A dict is close, but doesn't have attribute access nor such a nice constructor syntax.
A named tuple comes close too, but I don't want to create a new type for each combination of attributes.
Something like that would be handy to have sometimes. I could make one myself in a minute, but it sounds like something that might exist in Python already.
In Python 3.3, the standard solution is types.SimpleNamespace, but this is not backported to 2.7. A very similar type, argparse.Namespace exists in 2.7. It's a little obscure but documented and hence okay to rely on.
Going along with the subclassing solution, you could do something like this:
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = self
It looks a little weird, but it should work. It takes advantage of the builtin attribute location for python objects __dict__
>>>x = AttrDict(foo=1, bar=2)
>>>x.foo
1
>>>x.bar
2
>>>x.baz = 3
>>>x.baz
3
>>>x.missing
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'AttrDict' object has no attribute 'missing'
You can subclass dict to do something like this:(Thanks to #delnan, two such objects are already available in standard library)
class AttrDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, val):
self.__setitem__(attr, val)
...
>>> x = AttrDict(foo=1, bar=2)
>>> x.foo
1
>>> x.bar
2
>>> x.spam = 'eggs'
>>> x.spam
'eggs'
Are there any shortcuts for defining an empty object in Python or do you always have to create an instance of a custom empty class?
Edit: I mean an empty object usable for duck typing.
Yes, in Python 3.3 SimpleNamespace was added
Unlike object, with SimpleNamespace you can add and remove attributes. If a SimpleNamespace object is initialized with keyword arguments, those are directly added to the underlying namespace.
Example:
import types
x = types.SimpleNamespace()
x.happy = True
print(x.happy) # True
del x.happy
print(x.happy) # AttributeError. object has no attribute 'happy'
You can use type to create a new class on the fly and then instantiate it. Like so:
>>> t = type('test', (object,), {})()
>>> t
<__main__.test at 0xb615930c>
The arguments to type are: Class name, a tuple of base classes, and the object's dictionary. Which can contain functions (the object's methods) or attributes.
You can actually shorten the first line to
>>> t = type('test', (), {})()
>>> t.__class__.__bases__
(object,)
Because by default type creates new style classes that inherit from object.
type is used in Python for metaprogramming.
But if you just want to create an instance of object. Then, just create an instance of it. Like lejlot suggests.
Creating an instance of a new class like this has an important difference that may be useful.
>>> a = object()
>>> a.whoops = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'whoops'
Where as:
>>> b = type('', (), {})()
>>> b.this_works = 'cool'
>>>
One simple, less-terrifying-looking way to create an empty(-ish) object is to exploit the fact that functions are objects in Python, including Lambda Functions:
obj = lambda: None
obj.test = "Hello, world!"
For example:
In [18]: x = lambda: None
In [19]: x.test = "Hello, world!"
In [20]: x.test
Out[20]: 'Hello, world!'
You said it in the question, but as no answer mentioned it with code, this is probably one of the cleanest solutions:
class Myobject:
pass
x = Myobject()
x.test = "Hello, world!" # working
What do you mean by "empty object"? Instance of class object? You can simply run
a = object()
or maybe you mean initialization to the null reference? Then you can use
a = None
All the proposed solutions are somewhat awkward.
I found a way that is not hacky but is actually according to the original design.
>>> from mock import Mock
>>> foo = Mock(spec=['foo'], foo='foo')
>>> foo.foo
'foo'
>>> foo.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/.../virtualenv/local/lib/python2.7/site-packages/mock/mock.py", line 698, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'bar'
See the documentation of unittest.mock here.
You can use
x = lambda: [p for p in x.__dict__.keys()]
Then
x.p1 = 2
x.p2 = "Another property"
After
x()
# gives
# ['p1', 'p2']
And
[(p, getattr(x,p)) for p in x()]
# gives
# [('p1', 2), ('p2', 'Another property')]
Constructs a new empty Set object. If the optional iterable parameter is supplied, updates the set with elements obtained from iteration. All of the elements in iterable should be immutable or be transformable to an immutable using the protocol described in section Protocol for automatic conversion to immutable.
Ex:
myobj = set()
for i in range(1,10): myobj.add(i)
print(myobj)
In my opinion, the easiest way is:
def x():pass
x.test = 'Hello, world!'
If there is a desired type of the empty object, in other words, you want to create it but don't call the __init__ initializer, you can use __new__:
class String(object):
...
uninitialized_empty_string = String.__new__(String)
Source: https://stackoverflow.com/a/2169191/6639500.
I would something like this in Python:
result = SomeClass(some_argument)
Here is the catch though. I don't want the result to be an instance but an immutable object (int, for example). Basically the hole role of a class is returning a value calculated from the argument. I am using a class and not a function for DRY purposes.
Since the above code won't work because it will always return an instance of SomeClass what would be the best alternative?
My only idea is to have a static method, but I don't like it:
result = SomeClass.static_method(some_argument)
You can override __new__. This is rarely a good idea and/or necessary though ...
>>> class Foo(object):
... def __new__(cls):
... return 1
...
>>> Foo()
1
>>> type(Foo())
<type 'int'>
If you don't return an instance of cls, __init__ will never be called.
Basically class methods are the way to go if you have a factory method.
About the result - it really depends on what kind of immutability you seek, but basically namedtuple does a great job for encapsulating things and is also immutable (like normal tuples):
from collections import namedtuple
class FactoryClass(object):
_result_type = namedtuple('ProductClass', ['prod', 'sum'])
#classmethod
def make_object(cls, arg1, arg2):
return cls._result_type(prod=arg1 * arg2, sum=arg1 + arg2)
>>> FactoryClass.make_object(2,3)
ProductClass(prod=6, sum=5)
>>> x = _
>>> x.prod = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute