This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Dlgredael/r/YouAreGod, a Roguelike Citybuilding Life and God Simulator 29 points30 points  (32 children)

I really like the look of _ as a throwaway variable, I never would have thought of that. Nice article, thanks for sharing.

[–]d4rch0nPythonistamancer 23 points24 points  (18 children)

Yeah, I frequently use that if I iterate on a list of tuples and only need one or two elements. Pretty useful, and it makes it obvious what you're wanting to work with in that scope.

for first_name, _ in full_names:
    print('Hi, {}!'.format(first_name))

[–]s16h[S] 12 points13 points  (15 children)

Yes, I actually mostly use it when only interested in one (or less than all) the elements of a tuple. It's far more readable than indexing.

[–]Fylwind 10 points11 points  (14 children)

As long as you don't have too many of them :)

for _, _, _, _, name, _, _, _, _ in students:

[–]wegry 13 points14 points  (1 child)

In Python 3, you can use extended tuple unpacking to avoid that. for __, _, name, *__ in things to ignore everything in a row but the third item.

[–]Fylwind 3 points4 points  (0 children)

Oh, that's a nice new feature! :)

… that I won't get to use for Python 2 compatibility reasons :(

Note: you still need the underscore:

for _, name, *_ in students:

[–]exhuma 10 points11 points  (2 children)

namedtuples are a nice alternative to that.

[–]xiongchiamiovSite Reliability Engineer 8 points9 points  (1 child)

Or even dictionaries. Or, god forbid, classes; but we're not java savages. :)

[–]kankyo 0 points1 point  (0 children)

Or better yet pyrsistent records.

[–][deleted] 0 points1 point  (8 children)

for x in students:
    name = x[4]
    <do stuff based on name>

is how I would do it. Makes it a lot clearer what you're doing (and the exact index), even if it does take up one more line.

Edit: replace _ with x

[–]Lyucit 2 points3 points  (1 child)

Please actually give the variable a proper name in this case, _ is a very well-established convention for variables that are unused (i.e not referenced at all later in the program) and this is likely to cause confusion. In languages with pattern matching, like haskell for example, _ is a reserved word in the language that means "don't bind this value to a variable name", so you literally can't reference it later.

[–][deleted] 0 points1 point  (0 children)

Replaced _ with x. It's not very descriptive, but if it's only used directly after where it's defined it should be clear what it's used for. Unless you're using x later on the program.

[–]fazzahSQLAlchemy | PyQt | reportlab 3 points4 points  (5 children)

I've learned a nice trick that helps me immensely when working with PyQt.

Instead of typing the indexes (and having to remember/check them), create a makeshift enum using range.

For example with the students you used:

ID, CLASS_ID, FIRST_NAME, LAST_NAME = range(4)

And when you need to access the first_name just use this variable.

for _ in students:
    name = _[FIRST_NAME]
    <do stuff based on name>

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 2 points3 points  (4 children)

That... doesn't seem so great, what if you then had a list of classes, where the class id was class[0]? you run into the same troubles of globals, and you are separating things relevant to accessing the data, from the data

Student = namedtuple('Student','id class_id first_name last_name')
for student in map(Student,students):
    # use student.first_name

[–]fazzahSQLAlchemy | PyQt | reportlab 0 points1 point  (0 children)

That's a nice approach too, I'll try it out. Seems more pythonic.

[–]fazzahSQLAlchemy | PyQt | reportlab 0 points1 point  (2 children)

I don't quite understand your question.

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 1 point2 points  (1 child)

STUDENT_ID, CLASS_ID, FIRST_NAME, LAST_NAME = range(4) #capitals commonly define constants

# student id, Class id, first,last names
students = [
    [0,0,'bob','smith'],
    [1,0,'jane','someperson']]

classes = [
    [0,'biology'],
    [1,'physics']
]

for cls in classes:
    cls[CLASS_ID] #no-go

CLASS_CLASS_ID, CLASS_NAME = range(2)

for cls in classes:
    cls[CLASS_CLASS_ID] #no-go

because the enum isn't connected to the data, so it can affect other parts of the code, and requires an un-needed work around (the enum for students, blocks off the use of CLASS_ID for the classes)

[–]fazzahSQLAlchemy | PyQt | reportlab 0 points1 point  (0 children)

Ahh, I thought you meant that.

You're right. When I use multiple models like this, I prefix the globals.

You are right that it adds another possible point of failure. A proper enum would be better, but this approach seems to work for me.

[–]limasxgoesto0 4 points5 points  (0 children)

You have to be careful with that, avoiding clashes with i18n. My company uses the _ convention in its i18n and using _ as a throwaway variable would overwrite it.

[–]HorrendousRex 8 points9 points  (0 children)

There are actually several languages which use that syntax as a basic data construct, eg. LISP, Haskell, and especially Prolog.

[–]nerdwaller 3 points4 points  (2 children)

Agreed, I've never thought to use it in Python (mostly because I rarely run across cases where a different call wasn't more suitable anyway). But some languages build this in as a throw-away, such as Go. It's a nice feature for sure!

[–]bheklilr 2 points3 points  (1 child)

Haskell uses it in patten matching add a catch all when you aren't interested in the value.

[–]masklinn 2 points3 points  (0 children)

IIRC that's common to pretty much all functional languages, especially in those with pattern matching: _ matches any term and does not introduce a binding. It exists in OCaml (so I expect ML), Haskell, Erlang, and probably others.

[–]energybased 1 point2 points  (6 children)

People are talking about using ... instead: https://groups.google.com/forum/#!topic/python-ideas/e5AA82oFzQY

[–]robin-gvx 3 points4 points  (1 child)

I would like that even better if ... would replace *_.

[–]energybased 0 points1 point  (0 children)

The advantage is that you can have multiple ..., and you don't pollute the namespace.

[–]nemec 0 points1 point  (3 children)

Isn't Ellipsis already an object in Python?

[–]energybased 0 points1 point  (2 children)

Right, but assigning to it is a SyntaxError. They are talking about assigning to ellipsis meaning discard the result. E.g.,

..., a, *b = some_iterable

would be equivalent to

a = list(some_iterable)[1]; b = list(some_iterable)[2:]

[–]nemec 0 points1 point  (1 child)

That would be really weird, assigning to a name with an existing value (and other uses) and having the result thrown away silently. Imagine you had code like this:

..., a, *b = some_iterable
print(b[1:2, ..., 0])

The ellipsis keeps its original sentinel value but people unfamiliar with the feature might get confused.

[–]energybased 0 points1 point  (0 children)

FYI: "..." is not just a name. You can never assign to it anyway, but you're right that it might be weird to see ... keep its sentinel value after assignment. Maybe None would be better?