This question already has answers here:
How can I get a reversed copy of a list (avoid a separate statement when chaining a method after .reverse)?
(11 answers)
Closed 4 years ago.
I am a not an experienced programmer so please bear with me.I have been trying to solve this problem for hours to no avail. I would really appreciate a solution to my problem.
Create a program that will:
reverse the order of a list if the list consists of integers alone
Will convert the list items to uppercase if the list contains words
only.
Will return the same list if the list members don’t satisfy either of
these two criteria
Edit: This question is a duplicate
Here is my test code:
import unittest
import switchreverse
class Reverser(unittest.TestCase):
def test_Reverse(self):
word_lists = [1,2,3,4,5]
for e in word_lists:
if type(0):
assert word_lists.reverse()
if type(''):
assert word_lists.upper()
else:
return word_lists
if __name__ == '__main__':
unittest.main()
Here is the code being tested:
def Switchreverser():
word_lists = [1,2,3,4,5]
for e in word_lists:
if type(0):
word_lists.reverse()
elif type(''):
word_lists.upper()
else:
return word_lists
Here is the error I am recieving:
F
======================================================================
FAIL: test_Reverse (__main__.Reverser)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_switchreverse.py", line 8, in test_Reverse
assert word_lists.reverse()
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
list.reverse modifies list in-place and returns None, so assert list.reverse() is the same as assert None which obviously raises AssertionError.
Unrelated, but if type(0) and if type('') are not going to check the type of the lists' elements. Instead, you should be doing if all(isinstance(element, int) for element in list).
Related
Working with python3, I had a requirement:
Perform some pre-work
Do the core work
Cleanup the pre-work
Taking inspiration from fixtures in pytest I came across this post and wrote some crazy code.
Though this crazy code works, I wish to understand the yield sorcery that makes it working :)
def db_connect_n_clean():
db_connectors = []
def _inner(db_obj):
db_connectors.append(db_obj)
print("Connect : ", db_obj)
yield _inner
for conn in db_connectors:
print("Dispose : ", conn)
This is the driver code:
pre_worker = db_connect_n_clean()
freaky_function = next(pre_worker)
freaky_function("1")
freaky_function("2")
try:
next(pre_worker)
except:
pass
It produces this output:
Connect : 1
Connect : 2
Dispose : 1
Dispose : 2
Traceback (most recent call last):
File "junk.py", line 81, in <module>
next(pre_worker)
StopIteration
What confuses me in this code is, that all the calls to the same generator freaky_func is maintaining a single list of db_connectors
After the first yield, all the objects are disposed and I hit StopIteration
I was thinking that calling freaky_func twice would maintain 2 separate lists and there would be 2 separate yields
Update: The goal of this question is not to understand how to achieve this. As it is evident from the comments, context-manager is the way to go. But my question is to understand how this piece of code is working. Basically, the python side of it.
One of my favorite tools to visualize Python with is PythonTutor.
Basically, you can see that on the first run next(pre_worker) returns the _inner function. Since _inner is inside db_connect_n_clean, it can access all of its variables.
Internally, in Python, _inner contains a reference to db_connectors. You can see the reference under __closure__:
>>> gen = db_connect_n_clean()
>>> inner = next(gen)
>>> inner.__closure__
(<cell at 0x000001B73FE6A3E0: list object at 0x000001B73FE87240>,)
>>> inner.__closure__[0].cell_contents
[]
The name of the reference is the same as the variable:
>>> inner.__code__.co_freevars
('db_connectors',)
Every time this specific function, with this specific __closure__ tries to access the db_connectors, it goes to the same list.
>>> inner(1)
Connect : 1
>>> inner(2)
Connect : 2
>>> inner.__closure__[0].cell_contents
[1, 2]
The original generator gen() is still paused at the first yield:
>>> gen.gi_frame.f_lineno
6 # Gen is stopped at line #6
>>> gen.gi_frame.f_locals["db_connectors"]
[1, 2]
When you advance it again using next() it continues on from the yield and closes everything:
>>> next(gen)
Dispose : 1
Dispose : 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
If you wish to understand how do generators work in general, there are plenty of answers and articles on the subject. I wrote this one for example.
If I didn't fully explain the situation, feel free to ask for clarification in the comments!
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 1 year ago.
Originally, this question was "deepcopy a string in python" and I am keeping the essential parts of the discussion here for reference. Although I did solve the issue, I do not understand neither the origin of the issue nor how the solution differs from the wrong/not working implementation. I do want to understand this and took my time trimming the actual code into a minimal working example.
But first, part of original content: Deep copies of strings return the exact same string:
import copy
_1= "str"
_2 = copy.deepcopy(_str)
_1 is _2 # True
Novel content:
The questions are inline with the code. Basically, I am decorating a TestClass with a decorator that is going to generate standardized 'appender' methods on the class for every attribute inserted in TestClass.channels. Please note, I am not posting the question to discuss software architecture/implementation, but to actually understand the interstitials of Python relevant to the noted issue: why all 'appenders' generated will actually perform exactly the same work as that prepared for the last attribute of TestClass.channels defined:
import pandas as pd
def standardize_appenders(kls):
# Checks `kls` for `channels`, whether an appropriate pseudo implementation of 'appenders' is
# available and actually implements the `appenders`: BESIDES AUTOMATION, I AM FORCING A STANDARD
channels = getattr(kls, 'channels')
chs = [o for o in dir(channels) if not o.startswith('_')]
chs_type = [getattr(channels, o) for o in chs]
for _ch, _ch_type in zip(chs, chs_type): # ISSUE SOMEWHERE HERE
ch = _ch
ch_type = _ch_type
# THE `def appender(self, value, ch=ch, ch_type=ch_type)` SIGNATURE SOLVES THE PROB BUT I DON'T UNDERSTAND WHY
def appender(self, value):
# nonlocal ch, ch_type
if not isinstance(value, ch_type):
raise TypeError(f'`{ch}` only accepts values of `{ch_type}` type, but found {type(value)}')
data: dict = getattr(self, 'data') # let's not discuss the need for this knowledge please
data_list = data.setdefault(ch, [])
data_list.append(value)
data.setdefault(ch, data_list)
appender.__doc__ = f'<some {ch}/{ch_type}> specific docstring'
setattr(kls, 'append_' + ch, appender) # ALL APPENDERS OF `kls` WILL DO ESSENTIALLY THE WORK DEFINED LAST
return kls
#standardize_appenders
class TestClass:
class channels:
dataframe = pd.DataFrame
text = str
def __init__(self):
self.data = {}
if __name__ == '__main__':
test_inst = TestClass()
# test_inst.append_dataframe(pd.DataFrame({"col1": [1, 2, 3], "col2": list("abc")}))
# TypeError: `text` only accepts values of `<class 'str'>` type, but found <class 'pandas.core.frame.DataFrame'>
test_inst.append_dataframe("A minimal trimmed example") # NOTE THE WRONG 'APPENDER'
test_inst.append_text("of the original implementation")
print(test_inst.data)
# Out {'text': ['A minimal trimmed example', 'of the original implementation']}
Be my guest to propose a better title. I am out of good ideas for a short, but informative title for this case.
(Windows 10, python 3.8 from an anaconda env)
This question already has answers here:
TypeError: worker() takes 0 positional arguments but 1 was given [duplicate]
(11 answers)
Closed 4 years ago.
In testing multiple inheritance, I have the follow Date, Time and DateTime class heirarchy
class time:
def __init__(self, time):
self.time = time
def getTime():
return self.time;
class date:
def __init__(self, date):
self.date = date
def getDate():
return self.date
class datetime(time,date):
def __init__(self, input_time, input_date):
time.__init__(self, input_time)
date.__init__(self, input_date)
Instantiating and checking the date works fine:
my_datetime = datetime("12PM","Today")
my_datetime.date
'Today'
But running the getDate function yeilds a parameter error and I don't understand why
my_datetime.getDate()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-17-120ecf58a608> in <module>
----> 1 my_datetime.getDate()
TypeError: getDate() takes 0 positional arguments but 1 was given
Your issue has nothing to do with the multiple inheritance issue. In fact, you'd get exactly the same error trying to call getDate on an instance of date.
The cause of the issue is that you've forgotten to list self as an argument to getDate (and time.getTime as well). The instance the method gets called on will be passed automatically as the first positional argument, so you need to write the method with that in mind.
The error is telling you what is wrong. You've defined getDate to accept no parameters. When you do someObject.someMethod(), python automatically passes the object instance as the first parameter (almost universally named self).
If getDate should be called on an instance of the class, you need to define it like this:
def getDate(self):
...
Why is python shell throwing a NameError where as windows console a ValueError?
def PrintArgs(*arg):
list = ['1','2']
for i in arg:
try:
print(list[int(i)])
except ValueError:
print('Please enter integer value')
except NameError:
print('Name Error')
if __name__ == '__main__':
PrintArgs(*sys.argv[1:])
Providing the following arguments to Windows Console gives this output:
Here is how I call the code in windows console:
C:\>C:\Python34\python C:\Users\User\Documents\PYTest\Test.py 0 a
1
Please enter integer value
Providing the following arguments to Python Shell does not display the cusom error for NameError as mentioned in the code above, but mentions the following error:
PrintArgs(0,a)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
PrintArgs(0,a)
NameError: name 'a' is not defined
In the code example you've provided you define a list i, then you iterate over a collection called list you never initiated, and assign the values in this list to i, thus dropping the original value. I guess you only provided a part of your code, please provide a minimum working example.
If I try to reproduce your problem, I only get a type error, for iterating over a list which is not initialized.
OK So I have created 2 classes called Note and Notebook.
class Note:
""" A Note """
note_number = 1
def __init__(self, memo="", id=""):
""" initial attributes of the note"""
self.memo = memo
self.id = Note.note_number
Note.note_number += 1
def read_note(self):
print(self.memo)
class NoteBook:
"""The Notebook"""
def __init__(self):
self.note_book = []
def add_notes(self, *args):
for note in enumerate(args):
self.note_book.append(note)
def show_notes(self):
for note in self.note_book:
note.read_note()
n1 = Note("First note")
n2 = Note("Second note")
n3 = Note("Third note")
notebook1 = NoteBook()
notebook1.add_notes(n1, n2, n3)
notebook1.show_notes()
Traceback (most recent call last):
File "C:/Users/Alan/Python3/Random stuff/notebook revisions.py", line 47, in <module>
notebook1.show_notes()
File "C:/Users/Alan/Python3/Random stuff/notebook revisions.py", line 38, in show_notes
note.read_note()
AttributeError: 'tuple' object has no attribute 'read_note'
How come I get an attribute error? I want my show_notes() method to read all the notes in the notebook1 list.
Also if I print the following statement my result is the cryptic message:
print(notebook1.note_book[0])
(0, <__main__.Note object at 0x00863F30>)
How would I solve this problem to not produce the weird cryptic message and to print the strings "First note", "Second note" and "Third note".
Q1. Why the exception? As I suspected, the exception results from a bug in .add_notes. enumerate(args) turns notes into tuples containing a serial number and a note. This is wrong because notebooks should contain notes, not tuples, because notes already have a serial number, and because each call to add_note, and hence, enumerate, restarts at 0. Change add_note to
def add_notes(self, *args):
self.note_book.extend(args)
and notebook1.show_notes() produces what you seem to want.
First note
Second note
Third note
Q2. Better representation? For print(notebook1.note_book[0]) to print a tuple is wrong regardless of the content of the tuple. For testing, that line should have been part of the original script, just before the last line.
Printing a tuple prints the repr() of each element, so a custom __str__ will be ignored. With add_noted corrected, it now prints just the representation of the note.
<__main__.Note object at 0x00863F30>
To improve that, add back the __str__ method I asked you to delete, or a version thereof. I suggest you name it __repr__ instead, though.
def __repr__(self):
""" gives string of initial atrributes"""
return "Memo: {0}\nNote number: {1}\n ".format(self.memo, self.id)
# Note 1: First note
If you only define __str__, then __repr__ is still the mostly useless default (as above). If you define __repr__, then the custom function is used for both repr() and str(), the same as if you added the line __str__ = __repr__ after defining the latter.