Not specifying an actual name for positional argument in function definition - python

A single-parameter function can be written out like this:
import datetime
def func1(mydate):
frmt = '%d-%m-%Y'
return datetime.datetime.strptime(mydate, frmt)
The Python 3.5 interpreter also accepts this form of the same function:
def func2(str):
frmt = '%d-%m-%Y'
return datetime.datetime.strptime(str, frmt)
I am having trouble learning/researching why the latter single-parameter function works correctly.
Researching the web using phrases like "defining function with argument that is an actual type keyword", "type function as argument", etc., yields no information. If anybody is familiar with this behavior, or can direct me to a resource, I would be very grateful. Here is a verifiable example that can be pasted into the interpreter:
import datetime
def func1(mydate):
frmt = '%d-%m-%Y'
return datetime.datetime.strptime(mydate, frmt)
def func2(str):
frmt = '%d-%m-%Y'
return datetime.datetime.strptime(str, frmt)
# test
todaysdate = "28-10-2019"
print(func1(todaysdate) == func2(todaysdate))
Thank you for your help :)

Python doesn't stop you from "shadowing" built-in object types for variable names. It's not recommended of course. However, you're simply creating a variable with the name str.

I'll put this in an answer instead of leaving my comment but just to add upon the other answer. You aren't passing a type to your function, you are overwriting a built in type. Though python allows this, you shouldn't do it. It will lead to confusion and errors down the road.
def func(str):
print(str)
print(str(2))
func('test')
Output:
test
Traceback (most recent call last):
File "main.py", line 4, in <module>
func('test')
File "main.py", line 3, in func
print(str(2))
TypeError: 'str' object is not callable
Versus:
def func(my_str):
print(my_str) # prints test
print(str(2)) # prints 2
func('test')

import datetime
def func1(mydate):
frmt = '%d-%m-%Y'
return str(datetime.datetime.strptime(mydate, frmt))
def func2(str):
frmt = '%d-%m-%Y'
return str(datetime.datetime.strptime(str, frmt))
# test
todaysdate = "28-10-2019"
print(func1(todaysdate) == func2(todaysdate))
this program gives you overview of the error by overriding str() function.
just see monkey patching concept in python.
https://www.geeksforgeeks.org/monkey-patching-in-python-dynamic-behavior/

Related

Issues with 'self' argument and python requests module

Having an issue calling function dynamic_exit from class dynamic, called from an imported python file within the project file. Only including enough code to depict an efficient example of my issue.
Call example below:
from lib.core import dynamic
import ...
if requests.get(url).status_code != 200:
clear()
print(" xxxxx \n\n\n")
print("[ !! | Invalid URL ] Status code: {0}".format(
str(requests.get(url).status_code)))
time.sleep(1)
print("\n\n Please enter a valid URL.\nExiting...")
dynamic.dynamic_exit(self=dynamic())
time.sleep(3)
exit()
Lib.core contains:
class dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
def dynamic_load(self, loadSwitch=True):
self.loadSwitch = loadSwitch
done = False
for c in itertools.cycle(['[ | ]', '[ / ]', '[ - ]', '[ \\ ]']):
if done:
break
sys.stdout.write('\rLoading ' + c)
sys.stdout.flush()
time.sleep(0.1)
# Further along...
if dynamic.dynamic_analyze(): # Separate function -- Irrelevant
t = threading.Thread(target=dynamic_analyze())
t.start()
elif dynamic_exit(): # Separate function -- Irrelevant
t2 = threading.Thread(target=dynamic_exit())
t2.start()
else: # dynamic_load -- Example function
t3 = threading.Thread(target=dynamic_load())
t3.start()
sys.stdout.write('\r[ ✓ ] Process Complete ')
time.sleep(4.5)
done = True
loadSwitch = False
exitSwitch = False
analyzeSwitch = False
Lord, I know it's a mess. First time actually working with classes like this.
Error is as follows:
File "~/test-delete.py", line 11, in <module>
from lib.core import dynamic
File "~/lib/core.py", line 55, in <module>
if dynamic.dynamic_analyze():
TypeError: dynamic_analyze() missing 1 required positional argument: 'self'
The IDE is wanting more than a simple self parameter, it is recommending self=. So unsure of how to handle this.
Basically, need help under the context of the __init__ function and using the self parameter. Trying to call the function setting either exitSwitch, analyzeSwitch, or loadSwitch = True, ifswitch == True, perform either function dynamic_load, dynamic_exit, or dynamic_analyze. Post-completion, set all switches back to False.
The problem is that you are calling instance methods as if they are static methods. In other words, you call the methods as dynamic.dynamic_analyse() where dynamic is a reference to the class, not to an instance of that class.
So proceed as follows:
Name your class with PascalCase -- a common practice to distinguish classes from other things. So yours should be named Dynamic.
Create an instance and assign it to a variable. This one could actually get the name dynamic with lower case initial letter.
Don't pass an instance as argument when calling methods on the instance. Because in the notation a.b(), b will be called with the value for self set to a.
So define the class as:
class Dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
# ...etc.
Import the class and create an instance like this:
from lib.core import Dynamic
# ...
dynamic = Dynamic() # Create instance
# ...
if dynamic.dynamic_analyze(): # Call method on the instance
# ..etc
Your exit code should have:
dynamic.dynamic_exit() # No argument.
I cannot comment on the rest of your code, as it is hard to tell what it is doing. For instance, I do wonder why you call dynamic_analyse() twice... but this at least will solve the problem with the error you got.

Module 'self' has no attribute 'file' error in class format

I am building a python code to validate the email address and the phone number in a given CSV file using pandas and I want to write a separate CSV file with only the validated values. I am totally new to python and I have written a code for the functionality as follows:
from email_validator import validate_email, EmailNotValidError
import pandas as pd
import re
file = r'sample.csv'
filtered = r'filtered.csv'
valid = r'Valid.csv'
df=pd.read_csv(file)
def eVali(dataFrame):
try:
validate_email(dataFrame)
return True
except EmailNotValidError:
return False
def phoneValid(dataFrame):
if re.search("\w{3}-\w{3}-\w{4}",dataFrame):
return True
else:
return False
df["Email_validate"] = df['email'].apply(eVali)
df_fltrd = df[df['Email_validate']]
#del df_fltrd['Email_validate']
print(df_fltrd)
df_fltrd["Phone_validate"] =df_fltrd['phone'].apply(phoneValid)
df_valid = df_fltrd[df_fltrd["Phone_validate"]]
del df_valid["Phone_validate", "Email_validate"]
print(df_valid)
df_fltrd.to_csv(filtered)
df_valid.to_csv(valid)
This code is working fine and I could create a new CSV with validated values as I require. but when I tried to organize this code as a proper class with the proper method it gives an error saying,
Traceback (most recent call last):
File "E:\myTasks\validator.py", line 7, in <module>
class Validator:
File "E:\myTasks\validator.py", line 47, in Validator
validation(self.file)
AttributeError: module 'self' has no attribute 'file'
This is the class I created.
Validator.py
import self as self
from email_validator import validate_email, EmailNotValidError
import pandas as pd
import re
class Validator:
def __init__(self):
self.file = r'sample.csv'
self.outFile =r'filteredSample.csv'
def emailValid(dataframe):
try:
validate_email(dataframe)
return True
except EmailNotValidError:
return False
def phoneValid(dataframe):
if re.search("\w{3}-\w{3}-\w{4}", dataframe):
return True
else:
return False
def validation(self):
df = pd.read_csv(self.file)
df = df.copy();
df["Email_validate"] = df['email'].apply(Validator.emailValid)
df_filtered = df[df['Email_validate']]
print(df_filtered)
df_filtered["Phone_validate"] = df_filtered['phone'].apply(Validator.phoneValid)
df_valid = df_filtered[df_filtered["Phone_validate"]]
del df_valid["Email_validate"]
del df_valid["Phone_validate"]
print(df_valid)
df_valid.to_csv(self.outFile)
validation(self)
Can someone please help me with this. It will be really appreciated. Thanks in advance!
Well, you can't call an instance method from the class itself
validation(self)
This bit should be outside of your class, for example it could be called from your main function after having instantiated your Validator object.
my_validator = Validator()
my_validator.validation()
You do not import self.
self is the instance you are in at the time of code execution.
Your problem is that you did not understand classes yet. You tried to call a class method within the class which python does but toes not like.
I'd suggest you have a look at https://docs.python.org/3/tutorial/classes.html and/or https://www.w3schools.com/python/python_classes.asp.
You want to push the last line to the end and add
def main():
i = Validator()
i.validation()
if __name__ == "__main__":
main()

scope in class python

I have a class :
class Difference:
def __init__(self,a1):
self.a1=a1
def computeDifference(self):
d0=max([max(self.a1)-i for i in self.a1])
return d0
maximumDifference=d0
Now when i try to access the class like bellow getting bellow error:
_ = input().strip()
a = [int(e) for e in input().strip().split(' ')]
d = Difference(a)
d.computeDifference()
print(d.maximumDifference)
error:
Traceback (most recent call last):
File "q.py", line 2, in
class Difference:
File "q.py", line 8, in Difference
maximumDifference=d0
NameError: name 'd0' is not defined
what went wrong?
A few things:
You need to define what d0 is before you can assign it to maximumDifference.
And even if you do define d0 and try to assign it to maximumDifference it won't be reached because that line is after the return statemen.
incorrect indentation but that might be just how you posted your question. I edited your question to fix the indentation error
you can do something like this to fix the above problems:
def computeDifference(self):
d0=max([max(self.a1)-i for i in self.a1])
self.maximumDifference=d0
return d0
The above code would work But it is NOT good practice to define attribute outside of __init__. It is better to define class attributes inside of __init__
class Difference:
def __init__(self,a1):
self.a1=a1
self.maximumDifference = self.computeDifference()
def computeDifference(self):
d0=max([max(self.a1)-i for i in self.a1])
return d0
Your problem is with indentation. Python code must be well indented in order to work properly. Try:
class Difference:
def __init__(self,a1):
self.a1=a1
def computeDifference(self):
d0=max([max(self.a1)-i for i in self.a1])
self.maximumDifference=d0
return d0
Also the line maximumDifference=d0 would never be reached as it was placed after a return and, even if it was, your code wouldn't work since you're using only locally. To store and use maximumDifference outside that function you should store it in self.maximumDifference like the example above.

Python3.5 object and json.dumps() output

I wrote a class that would allow me to add days (integers) to dates (string %Y-%m-%d). The objects of this class need to be JSON serializable.
Adding days in the form of integers to my objects works as expected. However json.dumps(obj) returns too much info ("2016-03-23 15:57:47.926362") for my original object. Why ? How would I need to modify the class to get ""2016-03-23" instead ? Please see the example below.
Code:
from datetime import datetime, timedelta
import json
class Day(str):
def __init__(self, _datetime):
self.day = _datetime
def __str__(self):
return self.day.date().isoformat()
def __repr__(self):
return "%s" % self.day.date().isoformat()
def __add__(self, day):
new_day = self.day + timedelta(days=day)
return Day(new_day).__str__()
def __sub__(self, day):
new_day = self.day - timedelta(days=day)
return Day(new_day).__str__()
if __name__ == "__main__":
today = Day(datetime.today())
print(today) # 2016-03-23
print(json.dumps(today)) # "2016-03-23 15:57:47.926362"
print(today+1) # 2016-03-24
print(json.dumps(today+1)) # "2016-03-24"
print(today-1) # 2016-03-22
print(json.dumps(today-1)) # "2016-03-22"
Update. Here's my final code for those interested:
from datetime import datetime, timedelta
import json
class Day(str):
def __init__(self, datetime_obj):
self.day = datetime_obj
def __new__(self, datetime):
return str.__new__(Day, datetime.date().isoformat())
def __add__(self, day):
new_day = self.day + timedelta(days=day)
return Day(new_day)
def __sub__(self, day):
new_day = self.day - timedelta(days=day)
return Day(new_day)
if __name__ == "__main__":
today = Day(datetime.today())
print(type(today))
print(today) # 2016-03-23
print(json.dumps(today)) # "2016-03-23"
print(today + 1) # 2016-03-24
print(json.dumps(today + 1)) # "2016-03-24"
print(today - 1) # 2016-03-22
print(json.dumps(today - 1)) # "2016-03-22"
print(json.dumps(dict(today=today))) # {"today": "2016-03-23"}
print(json.dumps(dict(next_year=today+365))) # {"next_year": "2017-03-23"}
print(json.dumps(dict(last_year=today-366))) # {"last_year": "2015-03-23"}
Cool! Let's go with it. You are seeing:
print(json.dumps(today)) # "2016-03-23 15:57:47.926362"
Because somewhere in the encoding process, when deciding how to serialize what was passed to it, json.dumps calls isinstance(..., str) on your object. This returns True and your object is serialized like this string it secretly is.
But where does the "2016-03-23 15:57:47.926362" value come from?
When you call day = Day(datetime_obj), two things happen:
__new__ is called to instantiate the object. You haven't provided a __new__ method, so str.__new__ is used.
__init__ is called to initialize the object.
So day = Day(datetime_obj) effectively translates to:
day = str.__new__(Day, datetime_obj)
For json.dumps, your object will be a str, but the value of the str is set to the default string representation of datetime_obj. Which happens to be the full format you are seeing. Builtins, man!
I played around with this, and it seems if you roll your own __new__ (which is slightly exciting territory, tread carefully) which intercepts the str.__new__ call, you ~~should~~ be fine:
class Day(str):
def __new__(self, datetime):
return str.__new__(Day, datetime.date().isoformat())
But you didn't hear it from me if the whole thing catches fire.
PS The proper way would be to subclass JSONEncoder. But there is zero fun in it.
PS2 Oh, shoot, I tested this on 2.7. I may be completely out there, and if I am, just give me a "you tried" badge.
The reason for the json.dumps(today)'s behavior is not as obvious as it might appear at the first glance. To understand the issue, you should be able to answer two questions:
where does the string value that includes the time come from?
why Day.__str__ is not called by json encoder ? Should it?
Here're some prerequisites:
datetime.today() method is similar to datetime.now() -- it includes the current time (hour, minutes, etc). You could use date.today(), to get only date.
str creates immutable objects in Python; its value is set in the __new__ method that you have not overriden and therefore the default conversion str(datetime.today()) is used to initialize Day's value as a string. It creates the string value that includes both date and time in your case. You could override __new__, to get a different string value:
def __new__(cls, _datetime):
return str.__new__(cls, _datetime.date())
Day is a str subclass and therefore its instances are encoded as JSON strings
str methods return str objects instead of the corresponding subclass objects unless you override them e.g.:
>>> class S(str):
... def duplicate(self):
... return S(self * 2)
...
>>> s = S('abc')
>>> s.duplicate().duplicate()
'abcabcabcabc'
>>> s.upper().duplicate()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'duplicate'
s.upper() returns str object instead of S here and the following .duplicate() call fails.
In your case, to create the corresponding JSON string, json.dumps(today) performs an operation (re.sub() call in json.encode.encode_basestring()) on the today object that uses its value as a string i.e., the issue is that neither re.sub() nor encode_basestring() call __str__() method on instances of str subclasses. Even if encode_basestring(s) were as simple as return '"' + s + '"'; the result would be the same: '"' + today returns a str object and Day.__str__ is not called.
I don't know whether re module should call str(obj) in functions that accept isinstance(obj, str). Or whether json.encode.encode_basestring() should do it (or neither).
If you can't fix Day class; you could patch json.encode.encode_basestring() to call str(obj), to get a desirable JSON representation for str subtype instances (if you want to get the value returned by __str__() method -- putting aside whether it is wise to override __str__() on a str subclass in the first place):
import json
for suffix in ['', '_ascii']:
function_name = 'encode_basestring' + suffix
orig_function = getattr(json.encoder, function_name)
setattr(json.encoder, function_name, lambda s,_e=orig_function: _e(str(s)))
Related Python issue: Cannot override JSON encoding of basic type subclasses

TypeError: 'dict' object is not callable from main

I wrote a code which is going to store occurrences of words from a text file and store it to a dictionary:
class callDict(object):
def __init__(self):
self.invertedIndex = {}
then I write a method
def invertedIndex(self):
print self.invertedIndex.items()
and here is how I am calling:
if __name__ == "__main__":
c = callDict()
c.invertedIndex()
But it gives me the error:
Traceback (most recent call last):
File "E\Project\xyz.py", line 56, in <module>
c.invertedIndex()
TypeError: 'dict' object is not callable
How can I resolve this?
You are defining a method and an instance variable in your code, both with the same name. This will result in a name clash and hence the error.
Change the name of one or the other to resolve this.
So for example, this code should work for you:
class CallDict(object):
def __init__(self):
self.inverted_index = {}
def get_inverted_index_items(self):
print self.inverted_index.items()
And check it using:
>>> c = CallDict()
>>> c.get_inverted_index_items()
[]
Also check out ozgur's answer for doing this using #property decorator.
In addition to mu's answer,
#property
def invertedIndexItems(self):
print self.invertedIndex.items()
then here is how you'll cal it:
if __name__ == "__main__":
c = callDict()
print c.invertedIndexItems
Methods are attributes in Python, so you can't share the same name between them. Rename one of them.

Categories

Resources