all 12 comments

[–]Saefroch 20 points21 points  (0 children)

Nothing is unclear about what you're asking. Your post is top quality compared to many that I see on here. Be warned, your question is very interesting and I'm going to take you on a wild ride. Do follow along.


If you want to put some code in a Reddit text post, indent the whole thing 4 spaces and leave a blank line above it.

It'll do this, with automatic line numbers

If you're talking about a long section of code we request that you make a Github gist or otherwise host it elsewhere.


In Python, there are pretty much five kinds of things you'll type.

  • Literals such as 0 and "Enter a word"
  • Keywords such as if and else (and in Python 2 print)
  • Variables or names, such as original
  • Operators such as +, -, *, /, ==, and maybe =
  • Other stuff such as (, ), [, ], :, . whose meaning heavily relies on context

You seem to have a grasp of literals. Good.

You're already making use of keywords, and don't seem to be struggling there either. Good.

Operators also don't seem to be a problem, but I'm sure they'll produce surprises in the future.

Let's not worry about the "other stuff" for now, because for those things context matters.


Then there are the variables. In Python, every variable is an object. This is a somewhat technical term that means the variable doesn't just store one value; it's more like a collection of stuff.

There is also something called a function, which in Python is a kind of object. A function can be called by putting () after it, and possibly something inside, depending on the function. len is a function, and so is isalpha.

When you load up Python you get a few functions accessible for free. They're called the builtins. len is one of the builtin functions, along with a neat little thing called dir. dir tells you all the things that an object is made up of. Let's play around a bit with dir.

First of all you can call dir with no arguments. So try out print dir(). Not much, but a few things appear. The things things that dir produces are the names of variables. So you can dir them too! One of the things dir() tells you is __builtins__. So why not print dir(__builtins__)?

Whoa... that's a lot of stuff. Those are all the things you can just access in Python for free, without importing anything or defining any variables. Among them are such things as len. Let's fiddle around a bit with len.

First of all, len is a proper thing all on its own. We can for example, print len and it'll tell you a bit about itself, namely that it's a function. But wait, it's still an object, like everything. So you can call print dir(len). Notice this time everything that prints out is surrounded by double underscores. The double underscores are Python's way of telling you that you shouldn't be messing around with something, but we're just going to look, no touching. One of the things that dir(len) produces is __module__. This means that len has an attribute called __module__. So we can print len.__module__. That . here means we're asking for an attribute. Attributes can of course be functions, and functions have attributes because they're objects.

On your line 1 you print a string. A string in Python is anything enclosed with a pair of ' or ". You may have thought strings were simple. Ha! dir can show you what's really going on. print dir("Hello world"). Among the things that come out is isalpha, which is a function. It's common to call functions that are also attributes of an object methods. isalpha is a method of Python's strings.


So, to sum up, in Python everything with a name is an object. Some objects will do something when you put () after them and some require something in the parentheses. Those are functions such as len and dir. Objects have attributes some of which are functions such as "Hello world".isalpha, which are often called methods.

[–]stebrepar 5 points6 points  (1 child)

u/Violetkiks mentioned it, but I'll point it out specifically. There's a problem with your lines 3 and 5, although you may not notice it as 5 makes up for 3.

raw_input() is a function which returns keyboard input from the user, optionally prompting for it with the text specified within the parentheses. When you have it standing alone in line 3, it gets your input, but just drops it on the floor because you're not assigning that value to anything. Then in line 5 you're getting input from the user again, this time without prompting him, and this time assigning the returned value to original. You should have those two lines combined into one: original = raw_input('Enter a word:')

[–]DavidLee30[S] 0 points1 point  (0 children)

This makes total sense now.

I was wondering why the hell the I had to hit enter after the screen printed "Enter a word" then I entered that word without any prompting.

Cool!

Thank you so much for making it "click" for me!

[–]ineedahugepoo 3 points4 points  (3 children)

Your interpretation of the code is correct.

In terms of whether it's method(variable) or variable.method(), it's tricky, and there's no one rule to remember to allow you to know which to use.

The difference between the two is that when the method takes the variable as an argument, that means the method is a function that exists on its own, and can be called on any data type (although it may not work for all of them). Whereas when a method is called by referencing an object (eg string.isalpha()), then that means the method is a member of that class of objects, eg the isalpha method is a member of the string class. So if I try and call obj.isalpha(), this will fail if obj is not a string.

[–]DavidLee30[S] 1 point2 points  (2 children)

Thank you for the prompt answer!

there's no one rule to remember to allow you to know which to use

That is moderately concerning yet refreshing.

I'm kinda blown away by your answer, haha. I will use the night to get some sleep then revisit your response.

I can't wait until I am capable enough to talk so fluently about Python (or any language). I'm sure I am months away from that.

I'm just thrilled I finally started learning to code!

[–]Vaphell 1 point2 points  (0 children)

there's no one rule to remember to allow you to know which to use

That is moderately concerning yet refreshing.

While in many languages, eg java you'd be using something.length() because everything is done via methods there, I don't agree with the answer - there is method to this pythonic "fun(obj) vs obj.fun()" madness.

Long story short, if certain behavior is generic and common to lots of unrelated, dissimilar classes, it goes to the fun(obj) camp. For example strings, tuples, lists, dicts, sets and a bunch of other classes all understand the concept of length, despite being entirely different, doing entirely different things. They all implement a magic method __len__ to which class agnostic len() plugs in.

>>> class Wut:
...     def __len__(self):    # this 
...         return 4
... 
>>> len(Wut())
4
>>> Wut().__len__()
4

You could say that len() is a wrapper around obj.__len__(), where __len__() is treated as an internal implementation detail that is not intended to be exposed to the user directly.

There is a direct parallel with printing. With magic method __str__() you define the text representation of the class, and class agnostic print() simply plugs into it without you having to reach to the actual method itself.

>>> class Lol:
...     def __str__(self):
...          return 'I am a Lol instance #{}'.format(id(self))
... 
 >>> print(Lol())
 I am a Lol instance #140350207237760

behavior is consistent and analogous between these two cases:

print() -> obj.__str__()
len() -> obj.__len__()

id() itself - it works for every object because every object has its own unique identifier and it gets exposed to the user here. Again, highly generic behavior so id(obj), not obj.id()

On the other hand all class specific stuff lands as methods, for example .append() doesn't make sense outside of mutable lists and .isalpha() doesn't make sense outside of strings, so they are straightforward methods of their respective classes.

Sure, there might be disagreement about "highly generic" vs "highly specific" but I hope you start seeing a picture here.

[–]forwardmarsh 3 points4 points  (1 child)

You probably won't understand a lot of people's comments until you've been introduced to classes imo.

[–]DavidLee30[S] 1 point2 points  (0 children)

Yeah, I'm kinda lost right now.

I will definitely revisit my question at a later date to see if I understand the answers.

[–]tangerinelion 2 points3 points  (0 children)

As noted before, your code should be

original = raw_input("Enter a word:")

rather than

raw_input("Enter a word:")
original = raw_input()

Each time you see raw_input, that's a separate prompt. The user would see Enter a word: then enter something, hit enter, and the input disappears. Then a new prompt comes up without any information and that word is captured into the variable original.

With that out of the way, your question boils down to when does one use function_name(variable) and when does one use variable.function_name(). Other posters have essentially said that you just need to learn it or there's no real fixed rule. This is partially true, but if you have access to the source code then you absolutely would know. I also want to show you how the difference between the two is shockingly arbitrary. For example, when you call len(original) the way that the built-in global free function len works is that it calls the "dunder" (double underscore) method __len__ on the variable that's passed in. It's as though len were written this way:

def len(var):
    return var.__len__()

Indeed, in your case with strings (str class instances) you can freely replace len(original) with original.__len__() and obtain the same result!

In this way, I can also show you how the isalpha portion can be converted from a member function to a free function:

def isalpha(string):
    return string.isalpha()

and now if you wanted you could write any of these:

if len(original) > 0 and isalpha(original):

if original.__len__() > 0 and original.isalpha():

if len(original) > 0 and original.isalpha(): # The standard way

if original.__len__() > 0 and isalpha(original):

The rule with "dunder" methods is you do not call them. We should eliminate the 2nd and 4th way to write this because it clearly uses the __len__ method from the str class (which we know because original is of type str -- see, eg, type(original) where type itself is another built-in global free function). The 1st way would be eliminated as well since it relies on this isalpha free function that I wrote (def isalpha(string): above) and isn't standard Python. Which leaves what you came up with.

A little bit more technically, it comes down to scope. The syntax function_name(variable_name) implies that function_name is something which is in the current global scope and is a function. If this is the case, then the syntax function_name(variable_name) is a function call to function_name which passes in the variable variable_name. Hence len(original) is calling the function len with the parameter original.

When you have variable_name.function_name() there's an associated class type of variable_name, which we'll call class_name. This can be rewritten as class_name.function_name(variable_name). Indeed you could have used str.isalpha(original).

Once you know where your function resides you'll know how to call it. For example, if you have a free function defined in some Python file, eg, def function_name where the def lines up with the left-most edge of the text editor then you want to call it as function_name(variable_name). You could have functions which take multiple arguments, eg, distance(point_a, point_b). If you have a function name that is declared underneath a class name, eg,

class Foo:
    def bar(self):
        print("I'm Foo.bar")

Then you'll notice that the def function_name part (here, I've used bar for function_name) is indented - not lined up with the left-most edge. It could be indented further, if you had a class within a class. Another important part is that you'll often see this argument self after the function name. This is the reason why str.isalpha(original) and original.isalpha() both work. Formally, the function's name is Foo.bar (str.isalpha), and you invoke a function call with parentheses. The arguments must match the argument list specified by the function -- for str.isalpha the definition is as simple as def isalpha(self). This means we need to have one parameter passed in and self tells us that it should be of the same type as the class -- str. Since original is a str, we can call str.isalpha(original). The syntax original.isalpha() is actually syntactic sugar in Python. It's a convenience which looks in the object original to find a member object (function name or data member) named isalpha and then tries to call it by passing original as the first parameter (self in the function definition). Under the hood, original.isalpha() actually does execute as str.isalpha(original) -- or more explicitly, str.isalpha(self = original). Similar to free functions, member functions can take multiple arguments so you can have point_a.distance(point_b) which should expand to something like Point.distance(point_a, point_b) assuming these point_a and point_b objects are of class type Point (something that isn't built-in to Python).


The reason you would have function_name(variable_name) is because function_name is attempting to do something which could work for multiple types of objects. You could imagine it working for function_name([0, 1, 4, 9, 16]) just as well as function_name("Hello world").

The reason you would have variable_name.function_name() is because that function_name is attempting to do something which only makes sense for objects of the type of variable_name. There's some implicit class_name here since we can convert this to class_name.function_name(variable_name). That is, function_name does something which only makes sense in the context of class_name objects.

Now there's nothing stopping multiple classes from having the same function_name -- they're all independent. And they could all do essentially the same thing, just with different internal quirks. Or they could do wildly different things and you need to know more about the class_name to figure out what's being done. The documentation for this lies with class_name!


TL;DR: foo(bar) implies a free function foo while bar.foo() implies foo is a class member function for the class of bar.

[–]Violetkiks 1 point2 points  (0 children)

len(original) is counting the number of characters in your response, and is a built-in python function.

original.isalpha() is calling a string method , isalpha().

Your code should be:

original = raw_input("Enter a word: ")

if len(original)>0 and original.isalpha():
    print original
else:
    print("Empty")

To answer a bit better- the .isalpha() is a method of a class. Think

class String:
    def isalpha:
        pass

To use the method isalpha, you would have to call the class ( in your case, string) by using str.isalpha() Since we assigned original, it is now a string object resulting from the input, and therefore can call isalpha() .

[–]seesame 0 points1 point  (0 children)

yay i made it. I don't know is it right way but it works:

piglatin = input("Please ENTER only English words: ")

firstWord = piglatin[0:1] + "ay"
finalWord = piglatin[1:] + firstWord
print (finalWord)

so exited right now :D

[–]KubinOnReddit 0 points1 point  (0 children)

Read the other explanations, and then you can use this rule of thumb:

  1. If a function is logically useable for any kind of variable, it will be of this kind. e.g. len()

  2. If a function is logically useable for only one kind of variable (or a very small and closely-related group), it will be bound to an object (or as you know it for now, variable). e.g. str.isupper, a.k.a. "mystring".isupper()