why does this function not fire in the __init__ method? - python

class test:
def __init__(self, val):
self.val = val
self.val.lower()
Why doesn't lower() operate on the contents of val in this code?

You probably mean:
self.val = self.val.lower()
Or, more concisely:
class test:
def __init__(self, val):
self.val = val.lower()
To elaborate, lower() doesn't modify the string in place (it can't, since strings are immutable). Instead, it returns a copy of the string, appropriately modified.

The documentation states it pretty clearly:
Return a copy of the string with all the cased characters [4] converted to lowercase.

It is because strings are immutable. You cannot change them in-place.
Thus, you must overwrite the value of the variable like that:
self.val = self.val.lower()
Note: Unless, of course, your self.val is not a string, but rather some mutable object that is changed in-place after calling lower() method. But this is not the case (you can make it the case if you have created the class of self.val, though).
Example of mutable object with lower() method changing it in-place:
>>> class LowerableList(list):
def lower(self):
for i, item in enumerate(self):
self[i] = item.lower()
>>> a = LowerableList(['A', 'a', 'X', 'D'])
>>> a
['A', 'a', 'X', 'D']
>>> a.lower()
>>> a
['a', 'a', 'x', 'd']
Does it help?

In Python there are 2 types of function that leads to this kind of confusion. For example to sort a list you could do:
>>> a.sort()
or
>>> a = sorted(a)
first one sorts in "a", but second sorts "a" and returns new sorted list.

Related

How to create a sorted list or dictionary in python?

I want to create a list of string, and the elements are ordered by string length. For example:
my_list = ['a', 'bc', 'fef', 'cde', 'xxxx']
While I insert an element into this initial empty my_list, how to maintain such an order? In Java, I can create a custom order function and pass that as a constructor parameter.
I just found that this is the simplest way:
l = sorted(my_list, key=str.__len__)
One possible solution is using bisect.insort (doc). This function will insert value into list while maintaining sorted order:
from collections import UserString
from bisect import insort
class custom_string(UserString):
def __eq__(self, other):
return len(self) == len(other)
def __lt__(self, other):
return len(self) < len(other)
def insert(lst, s):
insort(my_list, custom_string(s))
my_list = []
insert(my_list, 'cde')
insert(my_list, 'a')
insert(my_list, 'bc')
insert(my_list, 'xxxx')
insert(my_list, 'fef')
print(my_list)
Prints:
['a', 'bc', 'cde', 'fef', 'xxxx']
EDIT: The values in the my_list are of type custom_string with custom __eq__ and __lt__ functions. To retype it back to normal string use for example str().
You can use a list with the heapq module to keep it "sorted"*.
import heapq
my_list = []
for value in ['a', 'bc', 'fef', 'cde', 'xxxx']:
heapq.heappush(my_list, value)
To supply a custom sort function, you can use a small wrapper:
class Heap(list):
"""
A lightweight heap essentially utilizing the heapq module.
It can however be supplied a key argument on initialization. The heap
itself is a list of tuples of (key, element), but popping is transparent.
"""
def __init__(self, initial=None, key=lambda x: x):
"""
Return an empty heap.
If it has the argument 'initial', it is assumed to be an iterable from
which the heap will be initialized.
'key' is a function similar to those usable in the sort() function,
which will be used whenever a comparison is made.
"""
self.key = key
if initial:
self.extend((key(item), item) for item in initial)
heapq.heapify(self)
def push(self, item):
"""Push an element on the heap."""
heapq.heappush(self, (self.key(item), item))
def pop(self):
"""Pop the smallest element off the heap, maintaining the invariant."""
return heapq.heappop(self)[1]
def replace(self, item):
"""
Pop an element off the heap, then push.
More efficient then first popping and then pushing.
"""
return heapq.heapreplace(self, (self.key(item), item))[1]
def pushpop(self, item):
"""
Push an element on the heap, then pop and return the smallest item.
More efficient then first pushing and then popping.
"""
return heapq.heappushpop(self, (self.key(item), item))[1]
Usage:
>>> my_heap = Heap(['a', 'bc', 'fef', 'cde', 'xxxx'])
>>> my_heap.push('fooooo')
*: The list behind the heap will not look sorted, but when using the heap interface it is.
You could use SortedList like this. You might have to install it sortedcontainer first to use it
from sortedcontainers import SortedList
x=['fef', 'cde', 'xxxx','a', 'bc']
sl = SortedList(x,key=lambda x: len(x))
list(sl) #['a', 'bc', 'fef', 'cde', 'xxxx']
You could simply sort it as you said in your post. However, if you want to insert a new incoming element at an appropriate index (by appropriate meaning, the insert should not disturb the increasing 'length' criteria) then below is also a simple function. I have assumed that you already have a list my_list = ['a', 'bc', 'fef', 'cde', 'xxxx'] and then you want to insert new strings from Random_Strings = ['b','ghij','fgh'].
import numpy as np
my_list = ['a', 'bc', 'fef', 'cde', 'xxxx']
Random_Strings = ['b','ghij','fgh']
def add_string_at_appropriate_index(ListWhereToInsert,StringToInsert):
Diff_of_Length = np.array([len(x)-len(StringToInsert) for x in ListWhereToInsert])
AppropriateIndex = np.where(Diff_of_Length==0)[0][0]
ListWhereToInsert.insert(AppropriateIndex,StringToInsert)
return ListWhereToInsert
for each_random_string in Random_Strings:
my_list = add_string_at_appropriate_index(my_list,each_random_string)
print(my_list)
When I run it I get an already sorted list after each insertion. No need to sort after every insertion. The output of the print is as below.
['b', 'a', 'bc', 'fgh', 'fef', 'cde', 'ghij', 'xxxx']
Just another way to do the same job (as has already been provided in this thread). May be useful to somebody in a particular situation. In this case you have already found a solution, so congrats!

Python Modify List outside scope of a class

I'm trying to call a function defined outside of class scope in Python, and it modifies the passed value, without any references to the passed variable, but somehow the original variable in class scope gets modified.
I have used python extensively for scriting but haven't really done much with Classes. I looked at this post, which explains a lot but doesn't really talk about it. This variable is surely out of scope, how's it getting mutated?
def doSomethingOutOfScope(arr):
spv = arr[0]
arr[0] = 'S'
class Solution:
def doSomethingInScope(self, passed_arr):
print(passed_arr) # prints [0, 1, 2]
doSomethingOutOfScope(passed_arr) # passed_arr shouldn't get modified
print(passed_arr) # prints ['S', 1, 2] - Why ?
s = Solution()
s.doSomethingInScope([0, 1, 2])
In Python, everything is an object and every object is passed in reference. Therefore basically any changes you directly made on the passed object besides reassigning is always reflected on the object itself in real time. The key thing to note is the mutability of the object, i.e. whether the object is mutable pass its initial assignment.
For example, str and int objects are immutable. Note there are never any methods under str and int that changes the object directly:
s = 'foo' # str type
s.upper() # FOO
print(s)
# foo
Note how str.upper() method doesn't change s itself. in order to make s into "FOO", you need to reassign s:
s = s.upper()
print(s)
# FOO
However by reassigning the object (obj = ...) it changes the object reference, where id(s) will now be different. So if a str was passed like this:
def func(string):
string = string.upper()
func(s)
s will remain unchanged because at the point of reassignment string = ..., string will no longer have the same object reference of s.
However, with mutable objects, as long as you don't reassign, the object itself will take the changes:
l = list('abcde')
def func(lst, value):
lst.append(value)
# no reassignment
func(l, 'f')
print(l)
# ['a', 'b', 'c', 'd', 'e', 'f']
That is because the object reference (id(l)) remains the same within the function.
All that said, in your case, if you wanted to do something with the object but not mutate it, you want to either pass a copy of the object (which will have a different id), or create a copy of the passed object in the local scope:
# pass a copy of the object:
def func(lst):
lst.append('x')
return lst
func(lst[:])
# OR, create a local object
def out_of_scope(lst):
temp_lst = lst[:]
temp_lst.append('x')
return temp_lst
In this particular case, [:] returns a full slice of the list as a different object.
For a bit more information, here's a relevant read.
Pythons list are actually mutable and are passed by reference

How to ignore specific elements being added to Python list

I have a python list. Let's say it's an empty list. Is there any way that I can make the list ignore specifc characters that when someone tries to add, at the time of list creation itself.
Suppose I want to ignore all the '.' characters to be ignored when someone tries to append the character usinng list.append('.').
Is there any way to mention that at the time of list creation itself?
I don't think you should do this, but if you really have to, you could subclass a list like so:
class IgnoreList(list):
def append(self, item, *args, **kwargs):
if item == '.':
return
return super(IgnoreList, self).append(item)
But is horribly un-pythonic. A better solution is to just check the value before calling append.
if value != '.':
my_list.append(value)
The best way to do this in python would be to create a new class with the desired behaviour
>>> class mylist(list):
... def append(self, x):
... if x != ".":
... super().append(x)
...
>>> l = mylist()
>>> l.append("foo")
>>> l
['foo']
>>> l.append(".")
>>> l
['foo']
You could create a special appending function which modifies the list in place if the character is not a '.':
def append_no_dot(l, c):
if c != '.': l.append(c)
>>> l = ['a','b']
>>> append_no_dot(l, 'c')
>>> append_no_dot(l, '.')
>>> l
['a', 'b', 'c']
class IgnoreList(list):
def __init__(self, ignore_me):
self.ignore_me = ignore_me
def check(self, v):
return v == self.ignore_me
def append(self, v):
if not self.check(v):
super(IgnoreList, self).append(v)
my_list = IgnoreList('x') # `x` to be ignored here
my_list.append('a')
my_list.append('b')
my_list.append('x')
my_list.append('c')
print my_list
######OUTPUT########
['a', 'b', 'c']

Make an array class using dictionaries only

I am a student who is new to python. I am trying to define an array class below which uses a dictionary as its only member variable. I am assuming that Python implements dictionaries as the only structured type (i.e., there is no array, list, tuple, etc.).
I am facing difficulty in coding such a program.
This is my code:
class array(object):
def __init__(self):
self.dic={}
def __init__(self,diction):
self.dic = {}
for x in diction:
self.dic.append(x)
def __setitem__(self,key,value):
self.dic[key]=value
def __getitem__(self,key):
if key not in self.dic.keys():
raise KeyError
return self.dic[key]
I want the program to work this way:
a = array('a','b','c') #------output------
print(a) # ['a', 'b', 'c']
print(a[1]) # b
a[1] = 'bee'
print(a) # ['a', 'bee', 'c']
a[3] = 'day'
print(a) # ['a', 'bee', 'c', 'day']
print(a[6]) # IndexError exception
Any suggestions, advice. :)
There are quite a few issues with your class definition:
array is already a data structure: better to rename using the proper Python class-naming conventions (MyClass).
You cannot overload function definitions: better to use an unpacking operator (*) to extract all (if any) arguments.
You cannot append to a dictionary: you need to assign to a key.
Your call to print will display a generic class name, since you don't specify a __str__ magic method. Since a dict is unordered, I did some funny business here to make it display as sorted, though I'm sure there's a better way.
No need to raise a KeyError in __getitem__, since this will be raised anyway.
Finally, I corrected your spacing.
Note that I've only implemented the methods necessary to make your test cases work.
class MyArray(object):
def __init__(self, *diction):
self.dic = {}
for i, x in enumerate(diction):
self.dic[i] = x
def __setitem__(self, key, value):
self.dic[key] = value
def __getitem__(self, key):
return self.dic[key]
def __str__(self):
return str([self.dic[i] for i in sorted(self.dic.keys())])

Python: return the index of the first element of a list which makes a passed function true

The list.index(x) function returns the index in the list of the first item whose value is x.
Is there a function, list_func_index(), similar to the index() function that has a function, f(), as a parameter. The function, f() is run on every element, e, of the list until f(e) returns True. Then list_func_index() returns the index of e.
Codewise:
>>> def list_func_index(lst, func):
for i in range(len(lst)):
if func(lst[i]):
return i
raise ValueError('no element making func True')
>>> l = [8,10,4,5,7]
>>> def is_odd(x): return x % 2 != 0
>>> list_func_index(l,is_odd)
3
Is there a more elegant solution? (and a better name for the function)
You could do that in a one-liner using generators:
next(i for i,v in enumerate(l) if is_odd(v))
The nice thing about generators is that they only compute up to the requested amount. So requesting the first two indices is (almost) just as easy:
y = (i for i,v in enumerate(l) if is_odd(v))
x1 = next(y)
x2 = next(y)
Though, expect a StopIteration exception after the last index (that is how generators work). This is also convenient in your "take-first" approach, to know that no such value was found --- the list.index() function would throw ValueError here.
One possibility is the built-in enumerate function:
def index_of_first(lst, pred):
for i,v in enumerate(lst):
if pred(v):
return i
return None
It's typical to refer a function like the one you describe as a "predicate"; it returns true or false for some question. That's why I call it pred in my example.
I also think it would be better form to return None, since that's the real answer to the question. The caller can choose to explode on None, if required.
#Paul's accepted answer is best, but here's a little lateral-thinking variant, mostly for amusement and instruction purposes...:
>>> class X(object):
... def __init__(self, pred): self.pred = pred
... def __eq__(self, other): return self.pred(other)
...
>>> l = [8,10,4,5,7]
>>> def is_odd(x): return x % 2 != 0
...
>>> l.index(X(is_odd))
3
essentially, X's purpose is to change the meaning of "equality" from the normal one to "satisfies this predicate", thereby allowing the use of predicates in all kinds of situations that are defined as checking for equality -- for example, it would also let you code, instead of if any(is_odd(x) for x in l):, the shorter if X(is_odd) in l:, and so forth.
Worth using? Not when a more explicit approach like that taken by #Paul is just as handy (especially when changed to use the new, shiny built-in next function rather than the older, less appropriate .next method, as I suggest in a comment to that answer), but there are other situations where it (or other variants of the idea "tweak the meaning of equality", and maybe other comparators and/or hashing) may be appropriate. Mostly, worth knowing about the idea, to avoid having to invent it from scratch one day;-).
Not one single function, but you can do it pretty easily:
>>> test = lambda c: c == 'x'
>>> data = ['a', 'b', 'c', 'x', 'y', 'z', 'x']
>>> map(test, data).index(True)
3
>>>
If you don't want to evaluate the entire list at once you can use itertools, but it's not as pretty:
>>> from itertools import imap, ifilter
>>> from operator import itemgetter
>>> test = lambda c: c == 'x'
>>> data = ['a', 'b', 'c', 'x', 'y', 'z']
>>> ifilter(itemgetter(1), enumerate(imap(test, data))).next()[0]
3
>>>
Just using a generator expression is probably more readable than itertools though.
Note in Python3, map and filter return lazy iterators and you can just use:
from operator import itemgetter
test = lambda c: c == 'x'
data = ['a', 'b', 'c', 'x', 'y', 'z']
next(filter(itemgetter(1), enumerate(map(test, data))))[0] # 3
A variation on Alex's answer. This avoids having to type X every time you want to use is_odd or whichever predicate
>>> class X(object):
... def __init__(self, pred): self.pred = pred
... def __eq__(self, other): return self.pred(other)
...
>>> L = [8,10,4,5,7]
>>> is_odd = X(lambda x: x%2 != 0)
>>> L.index(is_odd)
3
>>> less_than_six = X(lambda x: x<6)
>>> L.index(less_than_six)
2
you could do this with a list-comprehension:
l = [8,10,4,5,7]
filterl = [a for a in l if a % 2 != 0]
Then filterl will return all members of the list fulfilling the expression a % 2 != 0. I would say a more elegant method...
Intuitive one-liner solution:
i = list(map(lambda value: value > 0, data)).index(True)
Explanation:
we use map function to create a list containing True or False based on if each element in our list pass the condition in the lambda or not.
then we convert the map output to list
then using the index function, we get the index of the first true which is the same index of the first value passing the condition.

Categories