Can I create a view on a Python list?
There is no "list slice" class in the Python standard library (nor is one built-in). So, you do need a class, though it need not be big -- especially if you're content with a "readonly" and "compact" slice. E.g.:
import collections
class ROListSlice(collections.Sequence):
def __init__(self, alist, start, alen):
self.alist = alist
self.start = start
self.alen = alen
def __len__(self):
return self.alen
def adj(self, i):
if i<0: i += self.alen
return i + self.start
def __getitem__(self, i):
return self.alist[self.adj(i)]
This has some limitations (doesn't support "slicing a slice") but for most purposes might be OK.
To make this sequence r/w you need to add __setitem__
, __delitem__
, and insert
:
class ListSlice(ROListSlice):
def __setitem__(self, i, v):
self.alist[self.adj(i)] = v
def __delitem__(self, i, v):
del self.alist[self.adj(i)]
self.alen -= 1
def insert(self, i, v):
self.alist.insert(self.adj(i), v)
self.alen += 1
How do I create a view onto a NumPy array?
Sure, just index it as you normally would. E.g. y = x[:k, :]
This will return a view into the original array. No data will be copied, and any updates made to y
will be reflected in x
and vice versa.
Edit:
I commonly work with >10GB 3D arrays of uint8's, so I worry about this a lot... Numpy can be very efficient at memory management if you keep a few things in mind.
Here are a few tips on avoiding making copies of arrays in memory:
Use +=
, -=
, *=
, etc to avoid making a copy of the array. E.g. x += 10
will modify the array in place, while x = x + 10
will make a copy and modify it. (also, have a look at numexpr)
If you do want to make a copy with x = x + 10
, be aware that x = x + 10.0
will cause x
to automatically be up-casted to a floating point array, if it wasn't already. However, x += 10.0
, where x
is an integer array, will cause the 10.0
to be down-casted to an int of the same precision as the array, instead.
Additionally, many numpy functions take an out
parameter, so you can do things like np.abs(x, x)
to take the absolute value of x
in-place.
As a second edit, here's few more tips on views vs. copies with numpy arrays:
Unlike python lists, y = x[:]
does not return a copy, it returns a view. If you do want a copy (which will, of course, double the amount of memory you're using) use y = x.copy()
You'll often hear about "fancy indexing" of numpy arrays. Using a list (or integer array) as an index is "fancy indexing". It can be very useful, but copies the data.
As an example of this: y = x[[0, 1, 2], :]
returns a copy, while y = x[:3,:]
would return a view.
Even really crazy indexing like x[4:100:5, :-10:-1, None]
is "normal" indexing and will return a view, though, so don't be afraid to use all kinds of slicing tricks on large arrays.
x.astype(<dtype>)
will return a copy of the data as the new type, whilex.view(<dtype>)
will return a view.
Be careful with this, however... It's extremely powerful and useful, but you need to understand how the underlying data is stored in memory. If you have an array of floats, and view them as ints, (or vice versa) numpy will interpret the underlying bits of the array as ints.
For example, this means that 1.0
as a 64bit float on a little-endian system will be 4607182418800017408
when viewed as a 64bit int, and an array of [ 0, 0, 0, 0, 0, 0, 240, 63]
if viewed as a uint8. This is really nice when you need to do bit-twiddling of some sort on large arrays, though... You have low level control over how the memory buffer is interpreted.
Create a list with certain number of rows and columns in Python
You are first adding R0Cx
and then R1Cxy
. You need to add RxCy
. So try:
newlist = []
row = A
col = B
for x in range (0, row):
newlist.append([])
for y in range(0, col):
newlist[x].append('R' + str(x) + 'C' + str(y))
print(newlist)
how to utilize same list view for search and category queryset in django
Function-based View (FBV)
You can let the urls point to the same view (problem_list
) in the urlpatterns
:
urlpatterns = [
# ⋮,
path('datalist/search/', views.problemlist, name='problem_list_search'),
path('datalist/<slug:category_slug>/', views.problemlist, name='problem_list_category'),
# ⋮
]
Then in the view, we look if the category_slug
is set, and if that is not the case, we look for the ?name=…
query string part:
def problemlist(request, category_slug=None):
if category_slug is not None:
qs = DataModel.objects.get(category_slug=category_slug)
else:
DataModel.objects.filter(title__icontains=request.GET.get('name'))
return render(request,'list.html', {'qs':qs})
Class-based View (CBV)
You can also work with a class-based view, in that case you can define a subclass of a ListView
with:
from django.views.generic import ListView
class ProblemListView(ListView):
model = DataModel
template_name = 'list.html'
context_object_name = 'qs'
def get_queryset(self):
if 'category_slug' in self.kwargs:
return super().get_queryset().filter(
category_slug=self.kwargs['category_slug']
)
else:
return super().get_queryset().filter(
title__icontains=request.GET.get('name')
)
then we again make two paths that will invoke the same view:
urlpatterns = [
# ⋮,
path('datalist/search/', views.ProblemListView.as_view(), name='problem_list_search'),
path('datalist/<slug:category_slug>/', views.ProblemListView.as_view(), name='problem_list_category'),
# ⋮
]
Create an empty list with certain size in Python
You cannot assign to a list like xs[i] = value
, unless the list already is initialized with at least i+1
elements. Instead, use xs.append(value)
to add elements to the end of the list. (Though you could use the assignment notation if you were using a dictionary instead of a list.)
Creating an empty list:
>>> xs = [None] * 10
>>> xs
[None, None, None, None, None, None, None, None, None, None]
Assigning a value to an existing element of the above list:
>>> xs[1] = 5
>>> xs
[None, 5, None, None, None, None, None, None, None, None]
Keep in mind that something like xs[15] = 5
would still fail, as our list has only 10 elements.
range(x) creates a list from [0, 1, 2, ... x-1]
# 2.X only. Use list(range(10)) in 3.X.
>>> xs = range(10)
>>> xs
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Using a function to create a list:
>>> def display():
... xs = []
... for i in range(9): # This is just to tell you how to create a list.
... xs.append(i)
... return xs
...
>>> print display()
[0, 1, 2, 3, 4, 5, 6, 7, 8]
List comprehension (Using the squares because for range you don't need to do all this, you can just return range(0,9)
):
>>> def display():
... return [x**2 for x in range(9)]
...
>>> print display()
[0, 1, 4, 9, 16, 25, 36, 49, 64]
How to create widget list in python?
Step one: create an empty list
widget_list = []
Step two: add widgets to the list
for i in range(10):
button = tk.Button(root, text=f"Button #{i+1}", command=reset)
widget_list.append(button)
Step three: loop over the list to change the background:
for widget in widget_list:
widget.configure(background="red")
If the code in these steps are in separate functions, you'll need to declare widget_list
as global variable or an instance variable.
how to create a list of lists
Use append method, eg:
lst = []
line = np.genfromtxt('temp.txt', usecols=3, dtype=[('floatname','float')], skip_header=1)
lst.append(line)
Related Topics
How to Avoid Explicit 'Self' in Python
Numpy Sum Elements in Array Based on Its Value
Is the Server Bundled with Flask Safe to Use in Production
Interactive Input/Output Using Python
How to Sort Objects by Multiple Keys
Repeating Each Element of a Numpy Array 5 Times
Reading Unicode File Data with Bom Chars in Python
Accessing Mp3 Metadata with Python
Virtualenv --No-Site-Packages and Pip Still Finding Global Packages
How to Draw Intersecting Planes
How to Compare String and Integer in Python
Share Large, Read-Only Numpy Array Between Multiprocessing Processes