I know Python doesn't have pointers, but is there a way to have this yield 2 instead
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
?
Here's an example: I want form.data['field'] and form.field.value to always have the same value. It's not completely necessary, but I think it would be nice.
In PHP, for example, I can do this:
<?php
class Form {
public $data = [];
public $fields;
function __construct($fields) {
$this->fields = $fields;
foreach($this->fields as &$field) {
$this->data[$field['id']] = &$field['value'];
}
}
}
$f = new Form([
[
'id' => 'fname',
'value' => 'George'
],
[
'id' => 'lname',
'value' => 'Lucas'
]
]);
echo $f->data['fname'], $f->fields[0]['value']; # George George
$f->data['fname'] = 'Ralph';
echo $f->data['fname'], $f->fields[0]['value']; # Ralph Ralph
Output:
GeorgeGeorgeRalphRalph
ideone
Or like this in C++ (I think this is right, but my C++ is rusty):
#include <iostream>
using namespace std;
int main() {
int* a;
int* b = a;
*a = 1;
cout << *a << endl << *b << endl; # 1 1
return 0;
}
There's no way you can do that changing only that line. You can do:
a = [1]
b = a
a[0] = 2
b[0]
That creates a list, assigns the reference to a, then b also, uses the a reference to set the first element to 2, then accesses using the b reference variable.
I want form.data['field'] and
form.field.value to always have the
same value
This is feasible, because it involves decorated names and indexing -- i.e., completely different constructs from the barenames a and b that you're asking about, and for with your request is utterly impossible. Why ask for something impossible and totally different from the (possible) thing you actually want?!
Maybe you don't realize how drastically different barenames and decorated names are. When you refer to a barename a, you're getting exactly the object a was last bound to in this scope (or an exception if it wasn't bound in this scope) -- this is such a deep and fundamental aspect of Python that it can't possibly be subverted. When you refer to a decorated name x.y, you're asking an object (the object x refers to) to please supply "the y attribute" -- and in response to that request, the object can perform totally arbitrary computations (and indexing is quite similar: it also allows arbitrary computations to be performed in response).
Now, your "actual desiderata" example is mysterious because in each case two levels of indexing or attribute-getting are involved, so the subtlety you crave could be introduced in many ways. What other attributes is form.field suppose to have, for example, besides value? Without that further .value computations, possibilities would include:
class Form(object):
...
def __getattr__(self, name):
return self.data[name]
and
class Form(object):
...
#property
def data(self):
return self.__dict__
The presence of .value suggests picking the first form, plus a kind-of-useless wrapper:
class KouWrap(object):
def __init__(self, value):
self.value = value
class Form(object):
...
def __getattr__(self, name):
return KouWrap(self.data[name])
If assignments such form.field.value = 23 is also supposed to set the entry in form.data, then the wrapper must become more complex indeed, and not all that useless:
class MciWrap(object):
def __init__(self, data, k):
self._data = data
self._k = k
#property
def value(self):
return self._data[self._k]
#value.setter
def value(self, v)
self._data[self._k] = v
class Form(object):
...
def __getattr__(self, name):
return MciWrap(self.data, name)
The latter example is roughly as close as it gets, in Python, to the sense of "a pointer" as you seem to want -- but it's crucial to understand that such subtleties can ever only work with indexing and/or decorated names, never with barenames as you originally asked!
It's not a bug, it's a feature :-)
When you look at the '=' operator in Python, don't think in terms of assignment. You don't assign things, you bind them. = is a binding operator.
So in your code, you are giving the value 1 a name: a. Then, you are giving the value in 'a' a name: b. Then you are binding the value 2 to the name 'a'. The value bound to b doesn't change in this operation.
Coming from C-like languages, this can be confusing, but once you become accustomed to it, you find that it helps you to read and reason about your code more clearly: the value which has the name 'b' will not change unless you explicitly change it. And if you do an 'import this', you'll find that the Zen of Python states that Explicit is better than implicit.
Note as well that functional languages such as Haskell also use this paradigm, with great value in terms of robustness.
Yes! there is a way to use a variable as a pointer in python!
I am sorry to say that many of answers were partially wrong. In principle every equal(=) assignation shares the memory address (check the id(obj) function), but in practice it is not such. There are variables whose equal("=") behaviour works in last term as a copy of memory space, mostly in simple objects (e.g. "int" object), and others in which not (e.g. "list","dict" objects).
Here is an example of pointer assignation
dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}
Here is an example of copy assignation
a = 1
b = a # copy of memory mechanism. up to here id(a) == id(b)
b = 2 # new address generation. therefore without pointer behaviour
a
>>> 1
Pointer assignation is a pretty useful tool for aliasing without the waste of extra memory, in certain situations for performing comfy code,
class cls_X():
...
def method_1():
pd1 = self.obj_clsY.dict_vars_for_clsX['meth1'] # pointer dict 1: aliasing
pd1['var4'] = self.method2(pd1['var1'], pd1['var2'], pd1['var3'])
#enddef method_1
...
#endclass cls_X
but one have to be aware of this use in order to prevent code mistakes.
To conclude, by default some variables are barenames (simple objects like int, float, str,...), and some are pointers when assigned between them (e.g. dict1 = dict2). How to recognize them? just try this experiment with them. In IDEs with variable explorer panel usually appears to be the memory address ("#axbbbbbb...") in the definition of pointer-mechanism objects.
I suggest investigate in the topic. There are many people who know much more about this topic for sure. (see "ctypes" module). I hope it is helpful. Enjoy the good use of the objects! Regards, José Crespo
>> id(1)
1923344848 # identity of the location in memory where 1 is stored
>> id(1)
1923344848 # always the same
>> a = 1
>> b = a # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b) # equal to id(a)
1923344848
As you can see a and b are just two different names that reference to the same immutable object (int) 1. If later you write a = 2, you reassign the name a to a different object (int) 2, but the b continues referencing to 1:
>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880 # equal to id(2)
>> b
1 # b hasn't changed
>> id(b)
1923344848 # equal to id(1)
What would happen if you had a mutable object instead, such as a list [1]?
>> id([1])
328817608
>> id([1])
328664968 # different from the previous id, because each time a new list is created
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # now same as before
>> b = a
>> id(b)
328817800 # same as id(a)
Again, we are referencing to the same object (list) [1] by two different names a and b. However now we can mutate this list while it remains the same object, and a, b will both continue referencing to it
>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800 # same as before
>> id(b)
328817800 # same as before
From one point of view, everything is a pointer in Python. Your example works a lot like the C++ code.
int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl; // prints 1
(A closer equivalent would use some type of shared_ptr<Object> instead of int*.)
Here's an example: I want
form.data['field'] and
form.field.value to always have the
same value. It's not completely
necessary, but I think it would be
nice.
You can do this by overloading __getitem__ in form.data's class.
This is a python pointer (different of c/c++)
>>> a = lambda : print('Hello')
>>> a
<function <lambda> at 0x0000018D192B9DC0>
>>> id(a) == int(0x0000018D192B9DC0)
True
>>> from ctypes import cast, py_object
>>> cast(id(a), py_object).value == cast(int(0x0000018D192B9DC0), py_object).value
True
>>> cast(id(a), py_object).value
<function <lambda> at 0x0000018D192B9DC0>
>>> cast(id(a), py_object).value()
Hello
I wrote the following simple class as, effectively, a way to emulate a pointer in python:
class Parameter:
"""Syntactic sugar for getter/setter pair
Usage:
p = Parameter(getter, setter)
Set parameter value:
p(value)
p.val = value
p.set(value)
Retrieve parameter value:
p()
p.val
p.get()
"""
def __init__(self, getter, setter):
"""Create parameter
Required positional parameters:
getter: called with no arguments, retrieves the parameter value.
setter: called with value, sets the parameter.
"""
self._get = getter
self._set = setter
def __call__(self, val=None):
if val is not None:
self._set(val)
return self._get()
def get(self):
return self._get()
def set(self, val):
self._set(val)
#property
def val(self):
return self._get()
#val.setter
def val(self, val):
self._set(val)
Here's an example of use (from a jupyter notebook page):
l1 = list(range(10))
def l1_5_getter(lst=l1, number=5):
return lst[number]
def l1_5_setter(val, lst=l1, number=5):
lst[number] = val
[
l1_5_getter(),
l1_5_setter(12),
l1,
l1_5_getter()
]
Out = [5, None, [0, 1, 2, 3, 4, 12, 6, 7, 8, 9], 12]
p = Parameter(l1_5_getter, l1_5_setter)
print([
p(),
p.get(),
p.val,
p(13),
p(),
p.set(14),
p.get()
])
p.val = 15
print(p.val, l1)
[12, 12, 12, 13, 13, None, 14]
15 [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]
Of course, it is also easy to make this work for dict items or attributes of an object. There is even a way to do what the OP asked for, using globals():
def setter(val, dict=globals(), key='a'):
dict[key] = val
def getter(dict=globals(), key='a'):
return dict[key]
pa = Parameter(getter, setter)
pa(2)
print(a)
pa(3)
print(a)
This will print out 2, followed by 3.
Messing with the global namespace in this way is kind of transparently a terrible idea, but it shows that it is possible (if inadvisable) to do what the OP asked for.
The example is, of course, fairly pointless. But I have found this class to be useful in the application for which I developed it: a mathematical model whose behavior is governed by numerous user-settable mathematical parameters, of diverse types (which, because they depend on command line arguments, are not known at compile time). And once access to something has been encapsulated in a Parameter object, all such objects can be manipulated in a uniform way.
Although it doesn't look much like a C or C++ pointer, this is solving a problem that I would have solved with pointers if I were writing in C++.
The following code emulates exactly the behavior of pointers in C:
from collections import deque # more efficient than list for appending things
pointer_storage = deque()
pointer_address = 0
class new:
def __init__(self):
global pointer_storage
global pointer_address
self.address = pointer_address
self.val = None
pointer_storage.append(self)
pointer_address += 1
def get_pointer(address):
return pointer_storage[address]
def get_address(p):
return p.address
null = new() # create a null pointer, whose address is 0
Here are examples of use:
p = new()
p.val = 'hello'
q = new()
q.val = p
r = new()
r.val = 33
p = get_pointer(3)
print(p.val, flush = True)
p.val = 43
print(get_pointer(3).val, flush = True)
But it's now time to give a more professional code, including the option of deleting pointers, that I've just found in my personal library:
# C pointer emulation:
from collections import deque # more efficient than list for appending things
from sortedcontainers import SortedList #perform add and discard in log(n) times
class new:
# C pointer emulation:
# use as : p = new()
# p.val
# p.val = something
# p.address
# get_address(p)
# del_pointer(p)
# null (a null pointer)
__pointer_storage__ = SortedList(key = lambda p: p.address)
__to_delete_pointers__ = deque()
__pointer_address__ = 0
def __init__(self):
self.val = None
if new.__to_delete_pointers__:
p = new.__to_delete_pointers__.pop()
self.address = p.address
new.__pointer_storage__.discard(p) # performed in log(n) time thanks to sortedcontainers
new.__pointer_storage__.add(self) # idem
else:
self.address = new.__pointer_address__
new.__pointer_storage__.add(self)
new.__pointer_address__ += 1
def get_pointer(address):
return new.__pointer_storage__[address]
def get_address(p):
return p.address
def del_pointer(p):
new.__to_delete_pointers__.append(p)
null = new() # create a null pointer, whose address is 0
I don't know if my comment will help or not but if you want to use pointers in python, you can use dictionaries instead of variables
Let's say in your example will be
a = {'value': 1}
b = {'value': 2}
then you changed a to 2
a['value'] = 2
print(a) #{'value': 2}
Related
I know Python doesn't have pointers, but is there a way to have this yield 2 instead
>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1
?
Here's an example: I want form.data['field'] and form.field.value to always have the same value. It's not completely necessary, but I think it would be nice.
In PHP, for example, I can do this:
<?php
class Form {
public $data = [];
public $fields;
function __construct($fields) {
$this->fields = $fields;
foreach($this->fields as &$field) {
$this->data[$field['id']] = &$field['value'];
}
}
}
$f = new Form([
[
'id' => 'fname',
'value' => 'George'
],
[
'id' => 'lname',
'value' => 'Lucas'
]
]);
echo $f->data['fname'], $f->fields[0]['value']; # George George
$f->data['fname'] = 'Ralph';
echo $f->data['fname'], $f->fields[0]['value']; # Ralph Ralph
Output:
GeorgeGeorgeRalphRalph
ideone
Or like this in C++ (I think this is right, but my C++ is rusty):
#include <iostream>
using namespace std;
int main() {
int* a;
int* b = a;
*a = 1;
cout << *a << endl << *b << endl; # 1 1
return 0;
}
There's no way you can do that changing only that line. You can do:
a = [1]
b = a
a[0] = 2
b[0]
That creates a list, assigns the reference to a, then b also, uses the a reference to set the first element to 2, then accesses using the b reference variable.
I want form.data['field'] and
form.field.value to always have the
same value
This is feasible, because it involves decorated names and indexing -- i.e., completely different constructs from the barenames a and b that you're asking about, and for with your request is utterly impossible. Why ask for something impossible and totally different from the (possible) thing you actually want?!
Maybe you don't realize how drastically different barenames and decorated names are. When you refer to a barename a, you're getting exactly the object a was last bound to in this scope (or an exception if it wasn't bound in this scope) -- this is such a deep and fundamental aspect of Python that it can't possibly be subverted. When you refer to a decorated name x.y, you're asking an object (the object x refers to) to please supply "the y attribute" -- and in response to that request, the object can perform totally arbitrary computations (and indexing is quite similar: it also allows arbitrary computations to be performed in response).
Now, your "actual desiderata" example is mysterious because in each case two levels of indexing or attribute-getting are involved, so the subtlety you crave could be introduced in many ways. What other attributes is form.field suppose to have, for example, besides value? Without that further .value computations, possibilities would include:
class Form(object):
...
def __getattr__(self, name):
return self.data[name]
and
class Form(object):
...
#property
def data(self):
return self.__dict__
The presence of .value suggests picking the first form, plus a kind-of-useless wrapper:
class KouWrap(object):
def __init__(self, value):
self.value = value
class Form(object):
...
def __getattr__(self, name):
return KouWrap(self.data[name])
If assignments such form.field.value = 23 is also supposed to set the entry in form.data, then the wrapper must become more complex indeed, and not all that useless:
class MciWrap(object):
def __init__(self, data, k):
self._data = data
self._k = k
#property
def value(self):
return self._data[self._k]
#value.setter
def value(self, v)
self._data[self._k] = v
class Form(object):
...
def __getattr__(self, name):
return MciWrap(self.data, name)
The latter example is roughly as close as it gets, in Python, to the sense of "a pointer" as you seem to want -- but it's crucial to understand that such subtleties can ever only work with indexing and/or decorated names, never with barenames as you originally asked!
It's not a bug, it's a feature :-)
When you look at the '=' operator in Python, don't think in terms of assignment. You don't assign things, you bind them. = is a binding operator.
So in your code, you are giving the value 1 a name: a. Then, you are giving the value in 'a' a name: b. Then you are binding the value 2 to the name 'a'. The value bound to b doesn't change in this operation.
Coming from C-like languages, this can be confusing, but once you become accustomed to it, you find that it helps you to read and reason about your code more clearly: the value which has the name 'b' will not change unless you explicitly change it. And if you do an 'import this', you'll find that the Zen of Python states that Explicit is better than implicit.
Note as well that functional languages such as Haskell also use this paradigm, with great value in terms of robustness.
Yes! there is a way to use a variable as a pointer in python!
I am sorry to say that many of answers were partially wrong. In principle every equal(=) assignation shares the memory address (check the id(obj) function), but in practice it is not such. There are variables whose equal("=") behaviour works in last term as a copy of memory space, mostly in simple objects (e.g. "int" object), and others in which not (e.g. "list","dict" objects).
Here is an example of pointer assignation
dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}
Here is an example of copy assignation
a = 1
b = a # copy of memory mechanism. up to here id(a) == id(b)
b = 2 # new address generation. therefore without pointer behaviour
a
>>> 1
Pointer assignation is a pretty useful tool for aliasing without the waste of extra memory, in certain situations for performing comfy code,
class cls_X():
...
def method_1():
pd1 = self.obj_clsY.dict_vars_for_clsX['meth1'] # pointer dict 1: aliasing
pd1['var4'] = self.method2(pd1['var1'], pd1['var2'], pd1['var3'])
#enddef method_1
...
#endclass cls_X
but one have to be aware of this use in order to prevent code mistakes.
To conclude, by default some variables are barenames (simple objects like int, float, str,...), and some are pointers when assigned between them (e.g. dict1 = dict2). How to recognize them? just try this experiment with them. In IDEs with variable explorer panel usually appears to be the memory address ("#axbbbbbb...") in the definition of pointer-mechanism objects.
I suggest investigate in the topic. There are many people who know much more about this topic for sure. (see "ctypes" module). I hope it is helpful. Enjoy the good use of the objects! Regards, José Crespo
>> id(1)
1923344848 # identity of the location in memory where 1 is stored
>> id(1)
1923344848 # always the same
>> a = 1
>> b = a # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b) # equal to id(a)
1923344848
As you can see a and b are just two different names that reference to the same immutable object (int) 1. If later you write a = 2, you reassign the name a to a different object (int) 2, but the b continues referencing to 1:
>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880 # equal to id(2)
>> b
1 # b hasn't changed
>> id(b)
1923344848 # equal to id(1)
What would happen if you had a mutable object instead, such as a list [1]?
>> id([1])
328817608
>> id([1])
328664968 # different from the previous id, because each time a new list is created
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # now same as before
>> b = a
>> id(b)
328817800 # same as id(a)
Again, we are referencing to the same object (list) [1] by two different names a and b. However now we can mutate this list while it remains the same object, and a, b will both continue referencing to it
>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800 # same as before
>> id(b)
328817800 # same as before
From one point of view, everything is a pointer in Python. Your example works a lot like the C++ code.
int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl; // prints 1
(A closer equivalent would use some type of shared_ptr<Object> instead of int*.)
Here's an example: I want
form.data['field'] and
form.field.value to always have the
same value. It's not completely
necessary, but I think it would be
nice.
You can do this by overloading __getitem__ in form.data's class.
This is a python pointer (different of c/c++)
>>> a = lambda : print('Hello')
>>> a
<function <lambda> at 0x0000018D192B9DC0>
>>> id(a) == int(0x0000018D192B9DC0)
True
>>> from ctypes import cast, py_object
>>> cast(id(a), py_object).value == cast(int(0x0000018D192B9DC0), py_object).value
True
>>> cast(id(a), py_object).value
<function <lambda> at 0x0000018D192B9DC0>
>>> cast(id(a), py_object).value()
Hello
I wrote the following simple class as, effectively, a way to emulate a pointer in python:
class Parameter:
"""Syntactic sugar for getter/setter pair
Usage:
p = Parameter(getter, setter)
Set parameter value:
p(value)
p.val = value
p.set(value)
Retrieve parameter value:
p()
p.val
p.get()
"""
def __init__(self, getter, setter):
"""Create parameter
Required positional parameters:
getter: called with no arguments, retrieves the parameter value.
setter: called with value, sets the parameter.
"""
self._get = getter
self._set = setter
def __call__(self, val=None):
if val is not None:
self._set(val)
return self._get()
def get(self):
return self._get()
def set(self, val):
self._set(val)
#property
def val(self):
return self._get()
#val.setter
def val(self, val):
self._set(val)
Here's an example of use (from a jupyter notebook page):
l1 = list(range(10))
def l1_5_getter(lst=l1, number=5):
return lst[number]
def l1_5_setter(val, lst=l1, number=5):
lst[number] = val
[
l1_5_getter(),
l1_5_setter(12),
l1,
l1_5_getter()
]
Out = [5, None, [0, 1, 2, 3, 4, 12, 6, 7, 8, 9], 12]
p = Parameter(l1_5_getter, l1_5_setter)
print([
p(),
p.get(),
p.val,
p(13),
p(),
p.set(14),
p.get()
])
p.val = 15
print(p.val, l1)
[12, 12, 12, 13, 13, None, 14]
15 [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]
Of course, it is also easy to make this work for dict items or attributes of an object. There is even a way to do what the OP asked for, using globals():
def setter(val, dict=globals(), key='a'):
dict[key] = val
def getter(dict=globals(), key='a'):
return dict[key]
pa = Parameter(getter, setter)
pa(2)
print(a)
pa(3)
print(a)
This will print out 2, followed by 3.
Messing with the global namespace in this way is kind of transparently a terrible idea, but it shows that it is possible (if inadvisable) to do what the OP asked for.
The example is, of course, fairly pointless. But I have found this class to be useful in the application for which I developed it: a mathematical model whose behavior is governed by numerous user-settable mathematical parameters, of diverse types (which, because they depend on command line arguments, are not known at compile time). And once access to something has been encapsulated in a Parameter object, all such objects can be manipulated in a uniform way.
Although it doesn't look much like a C or C++ pointer, this is solving a problem that I would have solved with pointers if I were writing in C++.
The following code emulates exactly the behavior of pointers in C:
from collections import deque # more efficient than list for appending things
pointer_storage = deque()
pointer_address = 0
class new:
def __init__(self):
global pointer_storage
global pointer_address
self.address = pointer_address
self.val = None
pointer_storage.append(self)
pointer_address += 1
def get_pointer(address):
return pointer_storage[address]
def get_address(p):
return p.address
null = new() # create a null pointer, whose address is 0
Here are examples of use:
p = new()
p.val = 'hello'
q = new()
q.val = p
r = new()
r.val = 33
p = get_pointer(3)
print(p.val, flush = True)
p.val = 43
print(get_pointer(3).val, flush = True)
But it's now time to give a more professional code, including the option of deleting pointers, that I've just found in my personal library:
# C pointer emulation:
from collections import deque # more efficient than list for appending things
from sortedcontainers import SortedList #perform add and discard in log(n) times
class new:
# C pointer emulation:
# use as : p = new()
# p.val
# p.val = something
# p.address
# get_address(p)
# del_pointer(p)
# null (a null pointer)
__pointer_storage__ = SortedList(key = lambda p: p.address)
__to_delete_pointers__ = deque()
__pointer_address__ = 0
def __init__(self):
self.val = None
if new.__to_delete_pointers__:
p = new.__to_delete_pointers__.pop()
self.address = p.address
new.__pointer_storage__.discard(p) # performed in log(n) time thanks to sortedcontainers
new.__pointer_storage__.add(self) # idem
else:
self.address = new.__pointer_address__
new.__pointer_storage__.add(self)
new.__pointer_address__ += 1
def get_pointer(address):
return new.__pointer_storage__[address]
def get_address(p):
return p.address
def del_pointer(p):
new.__to_delete_pointers__.append(p)
null = new() # create a null pointer, whose address is 0
I don't know if my comment will help or not but if you want to use pointers in python, you can use dictionaries instead of variables
Let's say in your example will be
a = {'value': 1}
b = {'value': 2}
then you changed a to 2
a['value'] = 2
print(a) #{'value': 2}
I want to define constants, e.g. A = 10; B = 20, with these properties:
'Normal' access: e.g. A.value + B.value == 30 (or even A + B == 30)
Allow duplicate values: e.g. A = 10; B = 10
Associated string for each variable: e.g. A.name == "A"
Listing: e.g. [v.name for v in CONSTANTS]
IDE support: auto-complete names, re-factorizations, etc.
Adding a new constant requires one change
Importable: e.g. from config import CONSTANTS
In the end, the property #6 is the problem. Something like
A = 10
B = 20
A_NAME = "A"
B_NAME = "B"
CONSTANTS = { A_NAME: A, B_NAME: B }
would basically be the solution. But I would like to avoid this verbose code (if possible).
This attempt comes very close:
import enum
class CONSTANTS(enum.IntEnum):
A = 10
B = 20
assert CONSTANTS.A + CONSTANTS.B == 30
assert CONSTANTS.A.name == "A"
assert CONSTANTS.__members__.keys() == ["A", "B"]
assert CONSTANTS.__members__.values() == [10, 20]
but fails when two constants have the same value (property #2). One could also define a sub-class of Enum with a constructor taking value. But again, A = 10; B = 10 would be mapped to the same instance, even though the name differs. One could now also add a name (or any other unused, but distinctive parameter to the constructor) to make this problem go away. But I would consider this approach unclean. For instance, A = ("A", 10); B = ("B", 10); def __init__(self, _, value): ....
You can make the CONSTANTS dict thing less verbose by using globals() to copy the dict contents into global variables:
CONSTANTS = {"A": 10, "B": 20}
globals().update(CONSTANTS)
print(B) # prints 20
Have you considered using the namedtuple collection?
from collections import namedtuple
IntConst = namedtuple('IntConst', ['name', 'value'])
A = IntConst('A',10)
B = IntConst('B',20)
They meet your "Normal Access" by field....
A.value + B.value
They won't complain when multiple IntConst have the same value...
A = IntConst('A',10)
B = IntConst('B',10)
They will give an associated string ...
A.name
They will allow listing ...
CONSTANTS = list()
CONSTANTS.extend([A,B])
[v.name for v in CONSTANTS]
Your IDE probably already has support for namedtuple. Adding more constants simply requires you to create an instance of the IntConst namedtuple. As for importing, you'd simply create a list of those IntConst values in your namespace and they'd become valid targets for the import statement.
The only thing they don't give that you requested is the ability to duck type an integer value out of them. Instead, you'll get a tuple containing both IntConst instances.
>>> A+B
('A', 10, 'B', 10)
Disclaimer: Accessing a hidden attribute is discouraged and should thus not be considered a 'clean' solution!
The standard Enum module can be tweaked to provide the desired behavior.
import enum
class Const1(enum.Enum):
A = 42
B = 42
def __init__(self, size):
self._value_ = (self.name, size)
self.size = size
class Const2(enum.IntEnum):
A = 42
B = 42
def __init__(self, size):
enum.IntEnum.__init__(self)
self._value_ = (self.name, size)
Padding the _value_ attribute with the name of the member, renders the alias lookup mechanism unable to find other members with the same value. The only drawback is that the value attribute of the produced members all refer to their internal _value_ attribute. In fact, value is defined as a DynamicClassAttribute. Hence, without further modifications we face: Const1.A.value == ('A', 42).
If desired, a property can be used to overwrite this behavior.
#property
def value(self):
return self._value_[1]
What would be the equivalent of a C++ member pointer in Python? Basically, I would like to be able to replicate similar behavior in Python:
// Pointer to a member of MyClass
int (MyClass::*ptMember)(int) = &MyClass::member;
// Call member on some instance, e.g. inside a function to
// which the member pointer was passed
instance.*ptMember(3)
Follow up question, what if the member is a property instead of a method? Is it possible to store/pass a "pointer" to a property without specifying the instance?
One way would obviously be to pass a string and use eval. But is there a cleaner way?
EDIT: There are now several really good answers, each having something useful to offer depending on the context. I ended up using what is described in my answer, but I think that other answers will be very helpful for whoever comes here based on the topic of the question. So, I am not accepting any single one for now.
Assuming a Python class:
class MyClass:
def __init__(self):
self.x = 42
def fn(self):
return self.x
The equivalent of a C++ pointer-to-memberfunction is then this:
fn = MyClass.fn
You can take a method from a class (MyClass.fn above) and it becomes a plain function! The only difference between function and method is that the first parameter is customarily called self! So you can call this using an instance like in C++:
o = MyClass()
print(fn(o)) # prints 42
However, an often more interesting thing is the fact that you can also take the "address" of a bound member function, which doesn't work in C++:
o = MyClass()
bfn = o.fn
print(bfn()) # prints 42, too
Concerning the follow-up with the properties, there are plenty answers here already that address this issue, provided it still is one.
The closest fit would probably be operator.attrgetter:
from operator import attrgetter
foo_member = attrgetter('foo')
bar_member = attrgetter('bar')
baz_member = attrgetter('baz')
class Example(object):
def __init__(self):
self.foo = 1
#property
def bar(self):
return 2
def baz(self):
return 3
example_object = Example()
print foo_member(example_object) # prints 1
print bar_member(example_object) # prints 2
print baz_member(example_object)() # prints 3
attrgetter goes through the exact same mechanism normal dotted access goes through, so it works for anything at all you'd access with a dot. Instance fields, methods, module members, dynamically computed attributes, whatever. It doesn't matter what the type of the object is, either; for example, attrgetter('count') can retrieve the count attribute of a list, tuple, string, or anything else with a count attribute.
For certain types of attribute, there may be more specific member-pointer-like things. For example, for instance methods, you can retrieve the unbound method:
unbound_baz_method = Example.baz
print unbound_baz_method(example_object) # prints 3
This is either the specific function that implements the method, or a very thin wrapper around the function, depending on your Python version. It's type-specific; list.count won't work for tuples, and tuple.count won't work for lists.
For properties, you can retrieve the property object's fget, fset, and fdel, which are the functions that implement getting, retrieving, and deleting the attribute the property manages:
example_bar_member = Example.bar.fget
print example_bar_member(example_object) # prints 2
We didn't implement a setter or deleter for this property, so the fset and fdel are None. These are also type-specific; for example, if example_bar_member handled lists correctly, example_bar_member([]) would raise an AttributeError rather than returning 2, since lists don't have a bar attribute.
I was not satisfied with the string approach and did some testing. This seems to work pretty well and avoids passing strings around:
import types
# Our test class
class Class:
def __init__(self, val):
self._val = val
def method(self):
return self._val
#property
def prop(self):
return self._val
# Get the member pointer equivalents
m = Class.method
p = Class.prop
# Create an instance
c1 = Class(1)
# Bind the method and property getter to the instance
m1 = types.MethodType(m, c1)
p1 = types.MethodType(p.fget, c1)
# Use
m1() # Returns 1
p1() # Returns 1
# Alternatively, the instance can be passed to the function as self
m(c1) # Returns 1
p.fget(c1) # Returns 1
I'm not a C++ programmer, so maybe I'm missing some detail of method pointers here, but it sounds like you just want a reference to a function that's defined inside a class. (These were of type instancemethod in Python 2, but are just type function in Python 3.)
The syntax will be slightly different --- instead of calling it like a method with object.reference(args), you'll call it like a function: reference(object, args). object will be the argument to the self parameter --- pretty much what the compiler would have done for you.
Despite the more C-like syntax, I think it still does what you wanted... at least when applied to a callable member like in your example. It won't help with a non-callable instance field, though: they don't exist until after __init__ runs.
Here's a demonstration:
#!/usr/bin/env python3
import math
class Vector(object):
def __init__(self, x, y):
self.x = x
self.y = y
return
def __str__(self):
return '(' + str(self.x) + ', ' + str(self.y) + ')'
def __repr__(self):
return self.__class__.__name__ + str(self)
def magnitude(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
def print_dict_getter_demo():
print('Demo of member references on a Python dict:')
dict_getter = dict.get
d = {'a': 1, 'b': 2, 'c': 3, 'z': 26}
print('Dictionary d : ' + str(d))
print("d.get('a') : " + str(d.get('a')))
print("Ref to get 'a' : " + str(dict_getter(d, 'a')))
print("Ref to get 'BOGUS': " + str(dict_getter(d, 'BOGUS')))
print('Ref to get default: ' + str(dict_getter(d, 'BOGUS', 'not None')))
return
def print_vector_magnitude_demo():
print('Demo of member references on a user-defined Vector:')
vector_magnitude = Vector.magnitude
v = Vector(3, 4)
print('Vector v : ' + str(v))
print('v.magnitude() : ' + str(v.magnitude()))
print('Ref to magnitude: ' + str(vector_magnitude(v)))
return
def print_vector_sorting_demo():
print('Demo of sorting Vectors using a member reference:')
vector_magnitude = Vector.magnitude
v0 = Vector(0, 0)
v1 = Vector(1, 1)
v5 = Vector(-3, -4)
v20 = Vector(-12, 16)
vector_list = [v20, v0, v5, v1]
print('Unsorted: ' + str(vector_list))
sorted_vector_list = sorted(vector_list, key=vector_magnitude)
print('Sorted: ' + str(sorted_vector_list))
return
def main():
print_dict_getter_demo()
print()
print_vector_magnitude_demo()
print()
print_vector_sorting_demo()
return
if '__main__' == __name__:
main()
When run with Python 3, this produces:
Demo of member references on a Python dict:
Dictionary d : {'a': 1, 'c': 3, 'b': 2, 'z': 26}
d.get('a') : 1
Ref to get 'a' : 1
Ref to get 'BOGUS': None
Ref to get default: not None
Demo of member references on a user-defined Vector:
Vector v : (3, 4)
v.magnitude() : 5.0
Ref to magnitude: 5.0
Demo of sorting Vectors using a member reference:
Unsorted: [Vector(-12, 16), Vector(0, 0), Vector(-3, -4), Vector(1, 1)]
Sorted: [Vector(0, 0), Vector(1, 1), Vector(-3, -4), Vector(-12, 16)]
As you can see, it works with both builtins and user-defined classes.
Edit:
The huge demo above was based on an assumption: that you had a reference to the class, and that your goal was to "hold on to" to one of the class's methods for use on whatever instances of that class showed up sometime later.
If you already have a reference to the instance, it's much simpler:
d = {'a': 1, 'b': 2, 'c': 3, 'z': 26}
d_getter = d.get
d_getter('z') # returns 26
This is basically the same thing as above, only after the transformation from a function into a method has "locked in" the argument to self, so you don't need to supply it.
The way I would approach this in python is to use __getattribute__. If you have the name of an attribute, which would be the analog of the c++ pointer-to-member, you could call a.__getattribute__(x) to get the attribute whose name is stored in x. It's strings and dicts instead of offsets & pointers, but that's python.
this is my first question, and combined with my being fairly noob feel free to tell me if there is a completely different way I should be going about this!
Anyways, I am building a program that involves coloring a map with the four color theorem in Python 2.7, attempting to use certain colors as much as possible, and I ran into a problem when running something like this code:
In one module:
class state:
a = 0
b = 0
variable_list = [a,b]
Then I import that module into my main program:
from State import state //State(uppercase "s") is the .py file with the state class in it
instance = state()
instance.a = 1
print instance.variable_list[0]
...and the program prints 0, despite changing it in the main program. Any thoughts on how to update instance.variable_list with the change?
You have to think of Python variables in terms of pointers. Your question really boils down to the following:
>>> a = 42
>>> l = [a]
>>> a = 0
>>> print l[0] # shouldn't this print 0?
42
The answer is no, because re-assigning a has nothing to do with the list l. The list contains pointers to certain objects in memory. l[0] happens to be pointing to the same object as a (the int 42). When we reassign a, we simply have it "point" to a new object in memory (the int 0). This has no bearing on the list l.
It looks like this:
a = 42
l = [a]
+----+
a -----> | 42 | <------ l[0]
+----+
a = 0
+----+
l[0] ---> | 42 |
+----+
+---+
a ------> | 0 |
+---+
Notice that l[0] has not changed.
I'll cut to what I think you want to be doing.
class State(object):
def __init__(self):
self.a = 0
self.b = 0
#property
def variable_list(self):
return self.a, self.b
and usage:
state = State()
state.a = 1
state.variable_list
Out[23]: (1, 0)
Notable changes from your code:
You're grabbing an instance of State, so make the attributes instance attributes, not class attributes. I doubt you want every instance of State to share the same attributes.
#property decorator makes it so you can access variable_list just like it's a regular attribute, but you can customize the behavior of what it returns - in this case, a couple of instance attributes.
Inherit from object to get a "new-style" class. Trust me on this, there is essentially no reason to be using an old-style class nowadays.
Naming conventions. Classes start with upper case letters.
Let's take a look at your class code.
class state:
a = 0
b = 0
variable_list = [a,b]
a becomes 0, b becomes 0. Therefore, the list "variable_list" becomes [0, 0].
You then proceeded to change a using this code:
instance.a = 1
Which worked. The objects instance a variable is indeed 1. However, variable_list is still [0, 0]! The list remained it's original value because the list itself wasn't changed. The code you ran to make the list is only ran once. To solve this, you can make a function to update variable_list based on the current values of a and b (not the original values). For instance you can make a function to update the variable list like so:
def updateVariableList(self):
variable_list = [self.a, self.b]
when you call that function using instance.updateVariableList(), it will update the values of the list based on the current values of a and b. Now print instance.variable_list[0] will show the updated values.
When you update the variable a it does not update that instance but simply assigns it a different int with a completely different pointer. Therefore, this change does not reflect that change in the list as you expected it would.
You could either add a update method in your list that does:
def update():
variable_list = [a,b]
and call it every time you update your variables.
Or, you could simply use a dictionary and do away with individual variables:
class state:
variables = {'a': 0, 'b': 1}
x = state()
print x.variables['a']
x.variables['a'] = 1
print x.variables['a']
[OUTPUT]
0
1
Say I have a Python function that returns multiple values in a tuple:
def func():
return 1, 2
Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:
x, temp = func()
You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.
If you want to get multiple values at a time, use something like x, y = func()[2:4].
One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:
def f():
return 1, 2, 3
_, _, x = f()
If you're using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.
# Example 1: a is 1 and b is [2, 3]
a, *b = [1, 2, 3]
# Example 2: a is 1, b is [2, 3], and c is 4
a, *b, c = [1, 2, 3, 4]
# Example 3: b is [1, 2] and c is 3
*b, c = [1, 2, 3]
# Example 4: a is 1 and b is []
a, *b = [1]
The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.
However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:
x, __ = func()
Remember, when you return more than one item, you're really returning a tuple. So you can do things like this:
def func():
return 1, 2
print func()[0] # prints 1
print func()[1] # prints 2
The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:
def func():
return {'lat': 1, 'lng': 2}
latitude = func()['lat']
You could even use namedtuple if you want to add extra information about what you are returning (it's not just a dictionary, it's a pair of coordinates):
from collections import namedtuple
Coordinates = namedtuple('Coordinates', ['lat', 'lng'])
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you'll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?
Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:
from dataclasses import dataclass
#dataclass
class Coordinates:
lat: float = 0
lng: float = 0
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use #dataclass(frozen=True) instead of #dataclass to force them being immutable.
Here is a video that might help you pick the right data class for your use case.
Three simple choices.
Obvious
x, _ = func()
x, junk = func()
Hideous
x = func()[0]
And there are ways to do this with a decorator.
def val0( aFunc ):
def pick0( *args, **kw ):
return aFunc(*args,**kw)[0]
return pick0
func0= val0(func)
This seems like the best choice to me:
val1, val2, ignored1, ignored2 = some_function()
It's not cryptic or ugly (like the func()[index] method), and clearly states your purpose.
If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.
def func():
return 1, 2
func_ = lambda: func()[0]
func_() # Prints 1
This is not a direct answer to the question. Rather it answers this question: "How do I choose a specific function output from many possible options?".
If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the "common case" you don't even have to specify it.
def fancy_function( arg1, arg2, return_type=1 ):
ret_val = None
if( 1 == return_type ):
ret_val = arg1 + arg2
elif( 2 == return_type ):
ret_val = [ arg1, arg2, arg1 * arg2 ]
else:
ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 )
return( ret_val )
This method gives the function "advanced warning" regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple... whatever you like!
When you have many output from a function and you don't want to call it multiple times, I think the clearest way for selecting the results would be :
results = fct()
a,b = [results[i] for i in list_of_index]
As a minimum working example, also demonstrating that the function is called only once :
def fct(a):
b=a*2
c=a+2
d=a+b
e=b*2
f=a*a
print("fct called")
return[a,b,c,d,e,f]
results=fct(3)
> fct called
x,y = [results[i] for i in [1,4]]
And the values are as expected :
results
> [3,6,5,9,12,9]
x
> 6
y
> 12
For convenience, Python list indexes can also be used :
x,y = [results[i] for i in [0,-2]]
Returns : a = 3 and b = 12
It is possible to ignore every variable except the first with less syntax if you like. If we take your example,
# The function you are calling.
def func():
return 1, 2
# You seem to only be interested in the first output.
x, temp = func()
I have found the following to works,
x, *_ = func()
This approach "unpacks" with * all other variables into a "throwaway" variable _. This has the benefit of assigning the one variable you want and ignoring all variables behind it.
However, in many cases you may want an output that is not the first output of the function. In these cases, it is probably best to indicate this by using the func()[i] where i is the index location of the output you desire. In your case,
# i == 0 because of zero-index.
x = func()[0]
As a side note, if you want to get fancy in Python 3, you could do something like this,
# This works the other way around.
*_, y = func()
Your function only outputs two potential variables, so this does not look too powerful until you have a case like this,
def func():
return 1, 2, 3, 4
# I only want the first and last.
x, *_, d = func()