this post was submitted on 27 Jul 2024
27 points (93.5% liked)

Learn Programming

1638 readers
1 users here now

Posting Etiquette

  1. Ask the main part of your question in the title. This should be concise but informative.

  2. Provide everything up front. Don't make people fish for more details in the comments. Provide background information and examples.

  3. Be present for follow up questions. Don't ask for help and run away. Stick around to answer questions and provide more details.

  4. Ask about the problem you're trying to solve. Don't focus too much on debugging your exact solution, as you may be going down the wrong path. Include as much information as you can about what you ultimately are trying to achieve. See more on this here: https://xyproblem.info/

Icon base by Delapouite under CC BY 3.0 with modifications to add a gradient

founded 1 year ago
MODERATORS
 

Just started as in, I'm about an hour into a 4 hour intro video. Seeing two basic ways of manipulating things and don't understand the difference.

If I want to know the length of a string and I just guess at how to do it I would try one of these two things,

  1. Len(string)
  2. string.len()

What is the difference between these types of statements? How do I think about this to know which one I should expect to work?

all 21 comments
sorted by: hot top controversial new old
[–] [email protected] 15 points 3 months ago (1 children)

len is a built-in function: https://docs.python.org/3/library/functions.html#len

When you do len("something") you are passing the string something to it, and it returns how long it is. You can pass it other things like lists or sets, and it will tell you how many things are in them, too.

>>> len
<built-in function len>
>>> len("something")
9

>>> len([1,2,3,4])
4
>>> len({"a", "b", "c"})
3

If you were to try to do "something".len() it would try to call the function "len" that exists on str. There isn't one.

>>> "something".len()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'len'

https://docs.python.org/3/library/stdtypes.html#textseq

Scroll down a little to "String Methods" and you can see what methods are available on strings.

This is kind of language specific. Now you know that when you want to know how long something is in Python, you generally use the built-in len. If you're dealing with some other type of object, you'd check what methods it provides and what it inherits from. There's a lot of documentation reading in software development. A good IDE also helps.

[–] charolastra 3 points 3 months ago* (last edited 3 months ago) (1 children)

At the end of the day, len(ob) just defers to ob.__len__() so both are correct, just one's more functional and one's more object oriented.

[–] [email protected] 2 points 3 months ago* (last edited 3 months ago) (1 children)

Things prefixed with two underscores are considered private, and typically should not be accessed directly.

https://docs.python.org/3/tutorial/classes.html#private-variables

[–] charolastra 3 points 3 months ago* (last edited 3 months ago)

Keyword "typically". If I'm overriding dunder methods, then I'll typically need to call the super method as well. It's not like it's forbidden.

Consider the following:

class MyStr(str):
     def len(self):
          return len(self)
          # OR
          return self.__len__()

Both of the above return values are perfectly valid Python.

[–] FizzyOrange 12 points 3 months ago (1 children)

This is a great question. len(string) is the only one that works in Python but the choice is fairly arbitrary. Many other languages - probably most actually use the second form.

There are also languages that support "uniform function call syntax" where both work and are equivalent (e.g. D).

IMO the biggest advantage of the string.len() form is that it works with autocomplete. That may also explain why Python doesn't use it, because it didn't have static typing (and therefore proper auto-complete) until very recently. Many people still don't use it.

Note that even in Python the free function form len(string) is kind of a lie - it gets translated to string.__len__() so really they've just done both but made one of them really ugly.

Why? God knows. Python is full of insane design decisions. This is one of the milder ones.

[–] Rooki -1 points 3 months ago (1 children)

The first one is the approach of Functional Programming language (e.g. Python ) and the second one is the approach for Object orientated languages (e.g. Java, C#)

[–] FizzyOrange 8 points 3 months ago (1 children)

Python is not a functional language. It's highly imperative. For example if-else is a statement, not an expression.

An obvious counter-example is Rust which uses .len() and is a quite functional language (much more than Python).

Also object oriented languages aren't the "opposite" of functional languages. Guess what the O stands for in OCaml.

[–] Rooki -3 points 3 months ago (1 children)

Rust is Object Orientated Language.

Python is a function Orientated Language. ( Python 3 is less but its still has that orientation )
Because python is a scripting language and their Object Orientated Features are not that expanded like a "normal" Object Orientated Language like C# or Java.

https://en.wikipedia.org/wiki/Object-oriented_programming

[–] FizzyOrange 0 points 3 months ago

Not sure where to start with this but... no lol.

[–] [email protected] 4 points 3 months ago

What is the difference between these types of statements?

Technically, len() is a Python built-in function, while "some string".len() would be an instance method of a string object, if such an instance method existed.

How do I think about this to know which one I should expect to work?

As a very general rule of thumb, I would recommend to keep the list of built-in functions close and memorize the "popular ones" over time. These are special. Anything else you encounter usually is an instance or class method, or a plain function without any object-oriented shenanigans, depending on how structured the code is you are looking at.

Learn to navigate the Python reference docs. Use the search function liberally if you don't come from a search engine result, anyway, or jump directly to the docs for the module you're interested in to see what functionality it offers, and how to use it.

Python is annoyingly flexible, and does not strictly enforce a single way to do anything, so learning what to expect always ends up as building an intuition, and actively looking up documentation for the modules, classes, or functions you intend to use until you have encountered enough (good) Python code to have reasonable expectations in the first place.

TL;DR: grep the relevant module's docs, or Python built-ins. It's typically one or the other where you find detailed help.

[–] [email protected] 3 points 3 months ago* (last edited 3 months ago) (3 children)

len(string) passes the object 'string' to a function 'len' that returns its length.

sting.len() (edit: hypothetically if it existed) calls the method 'len' which is an inherent part of any object of string type.

In practice the result is the same, but the latter is the more object-oriented approach.

[–] [email protected] 4 points 3 months ago

Thanks this is helpful.

Function - probably has some limitations depending on what it is meant to do but generally I send a thing, it does it's function to that thing, and returns the result (or error).

Method - part of the thing itself. Would have to be defined for that 'object' and if it isn't then it probably doesn't make sense to ask for that info.

Probably have a ways to go to understand objects and why I would choose one VS the other.

[–] [email protected] 2 points 3 months ago

In python, string has no len method.

[–] [email protected] 1 points 3 months ago (2 children)

Follow up question. Are there any other ways I would find the length? Or are methods and functions the only options?

[–] [email protected] 3 points 3 months ago (2 children)

Are there any other ways I would find the length? Or are methods and functions the only options?

You could get creative and find several inferior, silly, and utterly insane ways of achieving the same result, for example by treating a string as an interable (read: "list" or "array") of its constituent characters, and count the number of characters. This feels very "example (but not exemplary) code on the first pages of a crappy C++ textbook", but hey, it's a way:

length = 0
string = "foobar"
for char in string:
  length = length + 1
print(length)

Mind you, this is not programming. This is toying around, and perfectly valid in that way, but no-one in a halfway sane state of mind would dare suggest doing it this way with Python if you actually care about the result. :)

[–] [email protected] 1 points 3 months ago (1 children)

Definitely don't want the extra complexity. Guess my question is if there is a third type of statement (function, method, ____) or maybe even more. From other replies it doesn't sound like it.

[–] [email protected] 2 points 3 months ago

I would not differentiate needlessly between the terms function and ["dunder", "instance", "module", "class"] method, this isn't practical at the current point in time, and arguably not pythonic. They are all callables and behave very similar for all practical purposes, all quacking like a duck.

If you want to deep-dive into the intricacies, there's technically a bunch of alternative "method types" with slightly differing calling and argument passing conventions. There are class methods, static methods, class properties, and module-scope functions off the top of my head, all very similar, but particularly suitable under specific circumstances.

If I wanted a String utility class, for example, I could have that:

class String:
  @staticmethod
  def len(string: str) -> int:
    if not isinstance(string, str):
      raise TypeError("Cannot determine length of non-string object")
    return len(string)

s = "foobar"
assert String.len(s) == 6

In Python I generally find static methods hardly as relevant as in other languages, and tend to create utility modules instead, with plain functions and maybe dataclasses for complex arguments or return values, which can then be imported and called pretty much the same way as a static method, but without the extra organisational class layer. I'd argue that's very much a matter of taste, and how much of a purebred OOP jockey you are, for better or worse.

Class properties are cool, however, you might want to look into that. It's getters/setters on crack, masquerading as their respective property, so that something like this "just works":

s = MyString("foobar")
assert s.len == 6
[–] [email protected] 1 points 3 months ago* (last edited 3 months ago)

Clearly you meant:

string = "foobar"
length = 0
_ = [length += 1 for _ in string]
print(length)

Much more readable!

Edit: Damn, doesn't work, was hoping to make something cursed but you can't make an assignment during comprehension. Oh well, maybe Python 3.14!

[–] [email protected] 1 points 3 months ago

There are definitely ways, IIRC str.len() is a function, but the double underscores basically mean "please don't call this directly". There might be other "hidden" variables tracking it, and if you wanted you could add a .length method to the string class at runtime

The beauty of python is it's pretty consistent in giving you one correct way to do things with the language, it will let you shoot yourself in the foot if you want to though

[–] [email protected] 2 points 3 months ago

You can't use string.len() on List Datatype iirc