Using None as parameter to keyword argument [duplicate] - python

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
python - returning a default value
I have a function in a class:
def foo(self, value = None):
if value is None:
return self.value
self.value = value
return self
This is a getter and setter combined into one, with the advantage that I can chain functions like this:
three = anInstanceOfMyClass.foo(3).bar().foo()
The problem appears when I do like this:
shouldBeNoneButIsThree = anInstanceOfMyClass.foo(3).foo(None).foo()
Here foo thinks that I did not pass an argument.
I can avoid this by:
Setting value to some strange object, like a random string
Create an object instance in the constructor which value has as default value
Both seem a bit too much work, what is an easier way?
setting value to something

You need to use a sentinel to detect that a default value was not set:
sentinel = object()
def foo(self, value=sentinel):
if value is not sentinel:
print("You passed in something else!")
This works because an instance of object() will always have it's own memory id and thus is will only return True if the exact value was left in place. Any other value will not register as the same object, including None.
You'll see different variants of the above trick in various different python projects. Any of the following sentinels would also work:
sentinel = []
sentinel = {}

Using a sentinel object value is fairly common; this is what the library does in abcoll.py:
__marker = object()
def pop(self, key, default=__marker):
...
if default is self.__marker:
Note that the sentinel object should be defined directly in the class.

Related

Pythonic way to get the first passed kwarg without knowing its name? [duplicate]

This question already has answers here:
Access an arbitrary element in a dictionary in Python
(14 answers)
Closed 3 years ago.
I have a function, which has a signature like this:
def func(**kwargs):
The user of that function will call the function with zero or one keyword arguments. If he passes one argument, the name will be foo_id, bar_id, baz_id etc., but I don't know the exact name he will use. The value of the passed argument will be some interger. I still want to take that argument's value and use it.
Currently I'm doing it like this, but I was wondering would there be a cleaner way to achieve this:
def func(**kwargs):
if kwargs:
target_id = list(kwargs.values())[0]
else:
target_id = None
# use target_id here, no worries if it's None
I'm using Python 3.8, so backwards compatibility is not an issue.
Here we are
def func(**kwargs):
target_id = next(iter(kwargs.values()), None)
print(target_id)
func(name_id='name')
func(value_id='value')
func(test_id='test')
func()
Outputs
python test.py
name
value
test
None
Since the dictionary has only one item, and you don't need to keep it in the dictionary, the cleanest way is to use the dict.popitem method. This returns both the argument name and its value as a pair.
def func(**kwarg):
if kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...
Since the caller should supply at most one argument, I recommend explicitly raising an error if it is called with more arguments:
def func(**kwarg):
if len(kwarg) > 1:
raise TypeError(f'Expected at most 1 keyword arg, got {len(kwarg)}.')
elif kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...

Python setattr() to function takes initial function name

I do understand how setattr() works in python, but my question is when i try to dynamically set an attribute and give it an unbound function as a value, so the attribute is a callable, the attribute ends up taking the name of the unbound function when i call attr.__name__ instead of the name of the attribute.
Here's an example:
I have a Filter class:
class Filter:
def __init__(self, column=['poi_id', 'tp.event'], access=['con', 'don']):
self.column = column
self.access = access
self.accessor_column = dict(zip(self.access, self.column))
self.set_conditions()
def condition(self, name):
# i want to be able to get the name of the dynamically set
# function and check `self.accessor_column` for a value, but when
# i do `setattr(self, 'accessor', self.condition)`, the function
# name is always set to `condition` rather than `accessor`
return name
def set_conditions(self):
mapping = list(zip(self.column, self.access))
for i in mapping:
poi_column = i[0]
accessor = i[1]
setattr(self, accessor, self.condition)
In the class above, the set_conditions function dynamically set attributes (con and don) of the Filter class and assigns them a callable, but they retain the initial name of the function.
When i run this:
>>> f = Filter()
>>> print(f.con('linux'))
>>> print(f.con.__name__)
Expected:
linux
con (which should be the name of the dynamically set attribute)
I get:
linux
condition (name of the value (unbound self.condition) of the attribute)
But i expect f.con.__name__ to return the name of the attribute (con) and not the name of the unbound function (condition) assigned to it.
Can someone please explain to me why this behaviour is such and how can i go around it?
Thanks.
function.__name__ is the name under which the function has been initially defined, it has nothing to do with the name under which it is accessed. Actually, the whole point of function.__name__ is to correctly identify the function whatever name is used to access it. You definitly want to read this for more on what Python's "names" are.
One of the possible solutions here is replace the static definition of condition with a closure:
class Filter(object):
def __init__(self, column=['poi_id', 'tp.event'], access=['con', 'don']):
self.column = column
self.access = access
self.accessor_column = dict(zip(self.access, self.column))
self.set_conditions()
def set_conditions(self):
mapping = list(zip(self.column, self.access))
for column_name, accessor_name in mapping:
def accessor(name):
print("in {}.accessor '{}' for column '{}'".format(self, accessor_name, column_name))
return name
# this is now technically useless but helps with inspection
accessor.__name__ = accessor_name
setattr(self, accessor_name, accessor)
As a side note (totally unrelated but I thought you may want to know this), using mutable objects as function arguments defaults is one of the most infamous Python gotchas and may yield totally unexpected results, ie:
>>> f1 = Filter()
>>> f2 = Filter()
>>> f1.column
['poi_id', 'tp.event']
>>> f2.column
['poi_id', 'tp.event']
>>> f2.column.append("WTF")
>>> f1.column
['poi_id', 'tp.event', 'WTF']
EDIT:
thank you for your answer, but it doesn't touch my issue here. My problem is not how functions are named or defined, my problem it that when i use setattr() and i set an attribute and i give it a function as it's value, i can access the value and perform what the value does, but since it's a function, why doesn't it return it's name as the function name
Because as I already explained above, the function's __name__ attribute and the name of the Filter instance attribute(s) refering to this function are totally unrelated, and the function knows absolutely nothing about the names of variables or attributes that reference it, as explained in the reference article I linked to.
Actually the fact that the object you're passing to setattr is a function is totally irrelevant, from the object's POV it's just a name and an object, period. And actually the fact you're binding this object (function or just whatever object) to an instance attribute (whether directly or using setattr(), it works just the same) instead of a plain variable is also totally irrelevant - none of those operation will have any impact on the object that is bound (except for increasing it's ref counter but that's a CPython implementation detail - other implementations may implement garbage collection diffently).
May I suggest you this :
from types import SimpleNamespace
class Filter:
def __init__(self, column=['poi_id', 'tp.event'], access=['con', 'don']):
self.column = column
self.access = access
self.accessor_column = dict(zip(self.access, self.column))
self.set_conditions()
def set_conditions(self):
for i in self.access:
setattr(self, i, SimpleNamespace(name=i, func=lambda name: name))
f = Filter()
print(f.con.func('linux'))
>>> linux
print(f.con.name)
>>> con
[edited after bruno desthuilliers's comment.]

Use __get__, __set__ with dictionary item?

Is there a way to make a dictionary of functions that use set and get statements and then use them as set and get functions?
class thing(object):
def __init__(self, thingy)
self.thingy = thingy
def __get__(self,instance,owner):
return thingy
def __set__(self,instance,value):
thingy += value
theDict = {"bob":thing(5), "suzy":thing(2)}
theDict["bob"] = 10
wanted result is that 10 goes into the set function and adds to the existing 5
print theDict["bob"]
>>> 15
actual result is that the dictionary replaces the entry with the numeric value
print theDict["bob"]
>>> 10
Why can't I just make a function like..
theDict["bob"].add(10)
is because it's building off an existing and already really well working function that uses the set and get. The case I'm working with is an edge case and wouldn't make sense to reprogram everything to make work for this one case.
I need some means to store instances of this set/get thingy that is accessible but doesn't create some layer of depth that might break existing references.
Please don't ask for actual code. It'd take pages of code to encapsulate the problem.
You could do it if you can (also) use a specialized version of the dictionary which is aware of your Thing class and handles it separately:
class Thing(object):
def __init__(self, thingy):
self._thingy = thingy
def _get_thingy(self):
return self._thingy
def _set_thingy(self, value):
self._thingy += value
thingy = property(_get_thingy, _set_thingy, None, "I'm a 'thingy' property.")
class ThingDict(dict):
def __getitem__(self, key):
if key in self and isinstance(dict.__getitem__(self, key), Thing):
return dict.__getitem__(self, key).thingy
else:
return dict.__getitem__(self, key)
def __setitem__(self, key, value):
if key in self and isinstance(dict.__getitem__(self, key), Thing):
dict.__getitem__(self, key).thingy = value
else:
dict.__setitem__(self, key, value)
theDict = ThingDict({"bob": Thing(5), "suzy": Thing(2), "don": 42})
print(theDict["bob"]) # --> 5
theDict["bob"] = 10
print(theDict["bob"]) # --> 15
# non-Thing value
print(theDict["don"]) # --> 42
theDict["don"] = 10
print(theDict["don"]) # --> 10
No, because to execute theDict["bob"] = 10, the Python runtime doesn't call any methods at all of the previous value of theDict["bob"]. It's not like when myObject.mydescriptor = 10 calls the descriptor setter.
Well, maybe it calls __del__ on the previous value if the refcount hits zero, but let's not go there!
If you want to do something like this then you need to change the way the dictionary works, not the contents. For example you could subclass dict (with the usual warnings that you're Evil, Bad and Wrong to write a non-Liskov-substituting derived class). Or you could from scratch implement an instance of collections.MutableMapping. But I don't think there's any way to hijack the normal operation of dict using a special value stored in it.
theDict["bob"] = 10 is just assign 10 to the key bob for theDict.
I think you should know about the magic methods __get__ and __set__ first. Go to: https://docs.python.org/2.7/howto/descriptor.html Using a class might be easier than dict.

Unexpected python behavior related to default argument for mutable object [duplicate]

This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 8 years ago.
#! /usr/bin/python
class my_class:
# 1. __init__
def __init__(self):
self.my_set = set()
# 2. __init__
#def __init__(self, arg_set = set()):
# self.my_set = arg_set
c1 = my_class()
c1.my_set.add('a')
print c1.my_set
c2 = my_class()
c2.my_set.add('b')
print c1.my_set
my_class has 2 ways of defining __init__:
If I use 1st way, output is as expected:
set(['a'])
set(['a'])
If I use 2nd way, output is unexpected:
set(['a'])
set(['a', 'b'])
What is wrong with 2nd way? How can modification of C2 (a separate object), result in modification of c1?
Edit: Updated the question title to reflect specific area of concern
From http://docs.python.org/2/reference/compound_stmts.html#function-definitions
Default parameter values are evaluated when the function definition is
executed. This means that the expression is evaluated once, when the
function is defined, and that the same “pre-computed” value is used
for each call. This is especially important to understand when a
default parameter is a mutable object, such as a list or a dictionary:
if the function modifies the object (e.g. by appending an item to a
list), the default value is in effect modified.
Thats the reason why your second method appends values everytime.
Moreover, modify the second __init__ like this
def __init__(self, arg_set = set()):
print id(arg_set)
self.my_set = arg_set
Now, when you run the code, you ll always get the same address (id function in CPython returns the address of the object in memory). So, default arguments are not created everytime the function is invoked, but when evaluated the first time.
thefourtheye is completely right on the cause of this behavior. If you want to use the second version of your constructor, it should be like this:
def __init__(self, arg_set=None):
if arg_set is None:
self.my_set = set()
else:
self.my_set = arg_set

How to assign cache to a method in an OOP fashion? [duplicate]

This question already has answers here:
What is memoization and how can I use it in Python?
(14 answers)
Closed 9 years ago.
Suppose that I have class A and this class has a method called function. Can I assign a cache as a property to this method? In the sense that I could call it like a property?
class A:
def __init__(self,value):
self.value=value
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
cache=[]
cache.append([a,a+1])
return a+1;
a=A(12)
print a.function(12)
print a.function.cache
Which gives me the error:
AttributeError: 'function' object has no attribute 'cache'
I know it is possible to assign a cache to the main class but I am looking for a possible way of assigning it as a property to the method object.
class A:
def __init__(self,value):
self.value=value
self.cache = {}
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
# Add a default value of empty string to avoid key errors,
# check if we already have the value cached
if self.cache.get(a,''):
return self.cache[a]
else:
result = a + 1
self.cache[a] = result
return result
As far as I know there is no way of having the cache as a property of the method. Python doesn't have such a feature. But I think perhaps this solution will satisfy your needs.
EDIT
Upon further research, there is indeed a way to do this in Python 3
class A:
def __init__(self,value):
self.value=value
def function(self,a):
"""function returns a+1 and caches the value for future calls."""
# Add a default value of empty string to avoid key errors,
# check if we already have the value cached
if self.function.cache.get(a,''):
return self.function.cache[a]
else:
result = a + 1
self.function.cache[a] = result
return result
function.cache = {}
a=A(12)
print(a.function(12))
print(a.function.cache)
This is because in Python 3 instance methods are just functions. BTW in Python 2 it is indeed possible to add attributes to functions, but not to instance methods. If you need to use Python 2 then there is a solution to your problem involving decorators that you should look into.

Categories