python .lower doesnt work without the (), im curious why - python

So I came across this but don't fully understand why this is the case:
count = 0
Got_one = 0
while(count<1):
print('\n')
response = input("Did you get one?\n:").lower()#<--This part here
if response == 'yes':
Got_one += 1
#...ect
At one point of the script I had typed up .lower without the (). The code ran fine but the script failed to +1 when I inputted "yes", instead it printed out a value of 0, most likely due to the "Got_one" variable being set to 0 in the very beginning. However, as soon as I typed up the () the code worked as intended and +1 to the value after inputting "yes".
So, why is this the case? Is .lower on its own lowering everything after it or just something I don't understand about Python yet?

.lower() is a built-in method for the String object in Python. The reason you need the parenthesis is to execute the function on the string.
Without the parenthesis, you are simply accessing the String.lower attribute, which is a function pointer. Therefore, without the parenthesis, you are setting response = String.lower, which will not pass the if statement.

the difference is that calling it with no parenthesis is your just calling the method but not the value of that method and calling it with parenthesis your calling the value of that method

The reason for that is because .lower() is a class method, not a class attribute (which would be written as .lower).
Therefore, you have to use parenthesis to indicate that you are trying to call a method.
Since it does not take any arguments, you simply only put empty parenthesis behind it.
A class method is a function that belongs to a class object, in this case a str object.
A class attribute is a variable that belongs to this object.

To add to 1313e's answer, .lower() is actually a built-in method (functions for object classes) that you're performing on the string object (because everything in Python is an object), which is why you call 'this string'.lower() and not, say, lower('this string')

This is because you are merely making a reference to the lower class method (function) of the class object str. For reference:
foo = "ALL CAPS"
bar = foo.lower
bar
>>> <built-in method lower of str object at 0x1038e1570>
bar()
>>> 'all caps'

Related

How can I add methods to floats and integers? [duplicate]

This question already has answers here:
What does it mean when the parentheses are omitted from a function or method call?
(6 answers)
Closed 2 years ago.
I'm a beginner to Python and programming in general. Right now, I'm having trouble understanding the function of empty parentheses at the end of method names, built-in or user-created. For example, if I write:
print "This string will now be uppercase".upper()
...why is there an empty pair of parentheses after "upper?" Does it do anything? Is there a situation in which one would put something in there? Thanks!
Because without those you are only referencing the method object. With them you tell Python you wanted to call the method.
In Python, functions and methods are first-order objects. You can store the method for later use without calling it, for example:
>>> "This string will now be uppercase".upper
<built-in method upper of str object at 0x1046c4270>
>>> get_uppercase = "This string will now be uppercase".upper
>>> get_uppercase()
'THIS STRING WILL NOW BE UPPERCASE'
Here get_uppercase stores a reference to the bound str.upper method of your string. Only when we then add () after the reference is the method actually called.
That the method takes no arguments here makes no difference. You still need to tell Python to do the actual call.
The (...) part then, is called a Call expression, listed explicitly as a separate type of expression in the Python documentation:
A call calls a callable object (e.g., a function) with a possibly empty series of arguments.
the parentheses indicate that you want to call the method
upper() returns the value of the method applied to the string
if you simply say upper, then it returns a method, not the value you get when the method is applied
>>> print "This string will now be uppercase".upper
<built-in method upper of str object at 0x7ff41585fe40>
>>>
upper() is a command asking the upper method to run, while upper is a reference to the method itself. For example,
upper2 = 'Michael'.upper
upper2() # does the same thing as 'Michael'.upper() !

Why does print(t) error if t.__str__() returns a non-string, but not print(t.__str__())?

I am trying to understand the __str__ method in Python.
class Test:
def __str__(self):
return 5
t = Test()
print(t.__str__())
In this method it returns an integer value but the print method is able to print it.
But, when I tried print(t) it threw the error TypeError: __str__ returned non-string (type int).
As I understand print(t) is also calling the __str__(self) method.
Why didn't print(t.__str__()) want the the string type conversion?
What you’re doing is equivalent to print(5), which works because print calls __str__ on 5 to get a string. But passing the object, print calls __str__ on the object and doesn’t get an actual string in response.
It's all about extra checks that python does with some built-in functions.
len() --> __len__() + some checks
str() --> __str__() + some checks
There is a difference between when "you" call a method explicitly or when that method gets called "by Python"! The point is when Python calls your method it will do some checks for you. (That's one of the reasons that we should use those built-in functions instead of calling relevant dunder method.)
We can see that behavior with len() and __len__() as well:
class Test:
def __len__(self):
return 'foo'
t = Test()
print(t.__len__()) # fine
print(len(t)) # TypeError: 'str' object cannot be interpreted as an integer
So python checked for returning integer in second print statement! that's what expected from __len__().
Same thing happens here. When you call print(t) Python itself calls __str__() method, so it does check to see if __str__() returns a string that is expected or not. (same thing happens with str(t))
But, when you say print(t.__str__()), first, you're calling it's __str__() method on the instance explicitly by yourself, there is no checking here... what does get back ? number 5, and then python will run print(5).
When you call t.__str__() directly it is just like any other method. The method __str__ method was overwritten, so there is nothing special about it when calling it directly.
When doing print(t) invocation happens internally, where some typechecking takes place
if (!PyUnicode_Check(res)) {
_PyErr_Format(tstate, PyExc_TypeError,
"__str__ returned non-string (type %.200s)",
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
The manual states:
The return value must be a string object.
so you should do something like
def __str__(self):
return str(5)
or better, something more meaningful like
def __str__(self) -> str:
return "TestObject with id: {}".format(self.id)
(The return type can be added to the function decalaration
so your editor will let you know if it doesn't have the right type.)
When you call print(t), print function tries to get the str(t) value which returns integer. The value has to be str, so it raises an exception. But when you call print(t.__str__()), it doesn't raise an exception because the method acts like an ordinary method and the return value type doesn't have to be str.
I will put here some finding that I found while looking at the behaviour of the print function. So, here goes nothing.
Why didn't print(t.str()) want the the string type conversion?
It actually does (but, I think not the way you expect it). As most people have noted here, what happened with the code, is that it will evaluate the __str__ function first (so, you got the number 5 here). And, what happened is that, it does the conversion (if you look at the source code here) using the __str__ of int class (so, your number 5 will be printed as "5")
But, when I tried print(t) it threw the error TypeError: str returned non-string (type int).
This happen because there is a checking to ensure the object "representated" as string properly. This behaviour can be checked on this source code
In theory, you are correct in this part:
As I understand print(t) is also calling the str(self) method.
Inside Python internal, when calling the __str__ method, Python does call the method __str__(self), but only one time, and it does get the result, a number 5:
https://github.com/python/cpython/blob/3.10/Objects/object.c#L499
But then, Python will check the result in C level, reports an error if the result is not a string:
https://github.com/python/cpython/blob/3.10/Objects/object.c#L505
It will not try to call __str__ method on the result again. So instead see the result, you will get the error TypeError: __str__ returned non-string (type int).

If strings in Python are immutable, why can I change a string in a function?

I'm new to Python, and I'm writing a function to change the case of all characters in a string. The function itself is called swapCases(), and I'm using the library function swapcase() within my own function. Here is the code that I use to test my function:
print(swapCases("HoLa"))
In the first case, my function reads:
def swapCases(s):
for i in range(len(s)):
s[i] = s[i].swapcase()
return s
When I run this code, I get a message from the compiler: "str object does not support item assignment." I Googled the message and it said that strings in Python are immutable and therefore can't be changed. However, when I change my function to this:
def swapCases(s):
s = s.swapcase()
return s
the function does exactly what I want, and the test prints out "hOlA." If strings are immutable in Python, why does this work? Doesn't being immutable mean that I can't change them?
By assigning it to the variable s, you are reassigning s. This gets rid of the reference to the old string "HoLa" and replaces it with a reference to the string returned from s.swapcases()
In your original case, you are attempting to modify the string index by index. Doing this would be mutating the existing references, which is not allowed. This is what is meant by immutable.
Your function is not modifying a string object. It's modifying a name assigned to it. When you assign directly, like this,
s = "abc"
s[2] = "z"
...you are saying "change the third character in this particular string object to 'z'." On the other hand, if you assign twice, like this,
s = "abc"
s = "abz"
...you are saying "change the name, s, to refer to a new string object." This applies whether it's created as a local variable (as above) or as a function argument.

Python String Comparison function()

I am checking a piece of Python code I found online (http://www.exploit-db.com/exploits/18305/), and I'm stuck over a piece of code.
To be honest I don't know Python, but I have experience in other programming languages.
The method _computeCollisionChars generates a number of characters and then adds them to a dictionary if they are different. Below is the method signature along with the relevant part for the question. Note: The actual code can be found on the linked source.
def _computeCollisionChars(self, function, count, charrange):
baseStr = ""
baseHash = function(baseStr) # What is this?
for item in source:
tempStr = ""
if tempStr == baseStr:
continue
if function(tempStr) == baseHash: # What type of comparison is this?
# logic goes here...
return
My questions are:
What does the function parameter mean in the method signature?
Most importantly what does function(string) do? Why are there two
checks, and what sort of output does function(tempStr) generate
then?
Thanks a lot guys!
Apparently you can pass any callable object as function to _computeCollisionChars. Then baseHash is initialised as the result of calling function with an empty string as parameter. Inside the loop, the condition reads: if the result of function called with an empty string as parameter equals the baseHash do this and that. Which is kind of senseless, because tempStr is always '' and baseHash never changes (or you didn't post that part).
In the current snippet the second if is never reached, because invariably tempStr == baseStr == ''.
As the commentors pointed out, in the real code tempStr and baseStr do indeed change and function is expected to be a hashing-function (but any other function which takes a string as argument should work).
In Python functions are first class objects, so they can be passed as arguments to other functions just fine. So function(baseStr) is calling the function object passed to _computeCollisionChars.
Note that Python doesn't check that it is a function object passed as an argument - it just implicitly expects this (and the program would crash it is wasn't, raising a TypeError exception).
>>> def f1():
print "Hello world"
>>> def f2(function):
function()
>>> f2(f1)
Hello World
>>> f2("not a callable function")
TypeError: 'str' object is not callable

Why different approach to Python string functions [duplicate]

This question already has answers here:
Why does Python code use len() function instead of a length method?
(7 answers)
Closed 8 years ago.
Just starting out with Python
Could anyone explain the reasoning behind why some built in string functions take arguments within their brackets like this:
length = len("This is a string")
whilst some other functions seem to just be "chained" on to the end of the string that they are operating on for example:
uppercase = "lowercase string".upper()
Probably a silly question but just wondered if there was a reason behind this that I'm unaware of.
len() is a built in function, it returns length of a sequence, that is you can pass lists, tuples to len() not only strings. For example:
foo = (1,2,3)
len(foo)
>>> 3
bar = ['a', 'b', 'c', 'd']
len(bar)
>>> 4
And about brackets - in your example what is between brackets is a string. You can also do this:
foo = "This is a string"
len(foo)
And the
"lowercase string".upper()
Is calling a method of a string object, which returns uppercase of that string. You can do the same with:
foo = "lowercase string"
uppercase = foo.upper()
the function len() is a buildin-function in the language. len() docs
and the .upper() function that your using is part of the string class. str.upper() docs
Len is a function, a built-in function, so using len (something) you apply a transformation to your input and obtain an output, something like Y=f(X).
"some string".upper() is a Method of the instance "some string"; "some string" belongs to the class String and has its methods.
Pay attention that "some string" written like that is an object and has all it's methods, you can see this if you type:
>>type("some string")
str
In summary: len is a function and is defined externally, .upper() is a method defined within the object itself
In the first case len is a function which you're calling within the current namespace, and you're passing a parameter to it. In the second, calling xyz.upper() means you are calling the method .upper() on the String object "lowercase string".
The len() function calls the __len__() method on the object passed in to it, so really it is just a shortcut for calling that method. Some other users have already posted links to the reasoning behind this (thank you for the correction larsmans).

Categories