Reference class variable in a comprehension of another class variable

2024/9/21 0:33:20

This may be a simple question, but I'm having trouble making a unique search for it.

I have a class that defines a static dictionary, then attempts to define a subset of that dictionary, also statically.

So, as a toy example:

class example(object): first_d = {1:1,2:2,3:3,4:4} second_d = dict((k,first_d[k]) for k in (2,3))

This produces NameError: global name 'first_d' is not defined

How should I be making this reference? It seems this pattern works in other cases, eg:

class example2(object):first = 1second = first + 1
Answer

A basic list comprehension has the following syntax

[expression for var in iterable]

When a list comprehension occurs inside a class, the attributes of the class can be used in iterable. This is true in Python2 and Python3.

However, the attributes of the class can be used (i.e. accessed) in expression in Python2 but not in Python3.

The story is a bit different for generator expressions:

(expression for var in iterable)

While the class attributes can still be accessed from iterable, the class attributes are not accessible from expression. (This is true for Python2 and Python3).

This can all be summarized as follows:

                             Python2      Python3
Can access class attributes
--------------------------------------------------
list comp. iterable                Y            Y
list comp. expression              Y            N
gen expr. iterable                 Y            Y
gen expr. expression               N            N
dict comp. iterable                Y            Y
dict comp. expression              N            N

(Dict comprehensions behave the same as generator expressions in this respect.)


Now how does this relate to your question:

In your example,

second_d = dict((k,first_d[k]) for k in (2,3))

a NameError occurs because first_d is not accessible from the expression part of a generator expression.

A workaround for Python2 would be to change the generator expression to a list comprehension:

second_d = dict([(k,first_d[k]) for k in (2,3)])

However, I don't find this a very comfortable solution since this code will fail in Python3.

You could do as Joel Cornett suggests:

second_d = {k: v for k, v in first_d.items() if k in (2, 3)}

since this uses first_d in the iterable rather than the expression part of the dict comprehension. But this may loop through many more items than necessary if first_d contains many items. Neverthess, this solution might be just fine if first_d is small.

In general, you can avoid this problem by defining a helper function which can be defined inside or outside the class:

def partial_dict(dct, keys):return {k:dct[k] for k in keys}class Example(object):first_d = {1:1,2:2,3:3,4:4}second_d = partial_dict(first_d, (2,3))class Example2(object):a = [1,2,3,4,5]b = [2,4]def myfunc(A, B):return [x for x in A if x not in B]c = myfunc(a, b)print(Example().second_d)
# {2: 2, 3: 3}print(Example2().c)
# [1, 3, 5]

Functions work because they define a local scope and variables in this local scope can be accessed from within the dict comprehension.

This was explained here, but I am not entirely comfortable with this since it does not explain why the expression part behaves differently than the iterable part of a list comprehension, generator expression or dict comprehension.

Thus I can not explain (completely) why Python behaves this way, only that this is the way it appears to behave.

https://en.xdnf.cn/q/72107.html

Related Q&A

Pyspark module not found

Im trying to execute a simple Pyspark job in Yarn. This is the code:from pyspark import SparkConf, SparkContextconf = (SparkConf().setMaster("yarn-client").setAppName("HDFS Filter")…

Multiple windows in PyQt4?

Ive just begun using pyqt4. I followed a tutorial (http://zetcode.com/tutorials/pyqt4/) One thing that puzzles me is this part:def main():app = QtGui.QApplication(sys.argv)ex = GUI()sys.exit(app.exec()…

Fill missing timeseries data using pandas or numpy

I have a list of dictionaries which looks like this :L=[ { "timeline": "2014-10", "total_prescriptions": 17 }, { "timeline": "2014-11", "total_…

Can Biopython perform Seq.find() accounting for ambiguity codes

I want to be able to search a Seq object for a subsequnce Seq object accounting for ambiguity codes. For example, the following should be true:from Bio.Seq import Seq from Bio.Alphabet.IUPAC import IUP…

MySQL and lock a table, read, and then truncate

I am using mysqldb in python.I need to do the following for a table.1) Lock 2) Read 3) Truncate the table 4) UnlockWhen I run the below code, I get the below error. So, I am rather unsure on how to lo…

Train and predict on variable length sequences

Sensors (of the same type) scattered on my site are manually reporting on irregular intervals to my backend. Between reports the sensors aggregate events and report them as a batch. The following datas…

What should a Python project structure look like for Travis CI to find and run tests?

I currently have a project with the following .travis.yml file:language: python install: "pip install tox" script: "tox"Locally, tox properly executes and runs 35 tests, but on Trav…

Having trouble building a Dns Packet in Python

Im trying to build a dns packet to send over a socket. I dont want to use any libraries because I want direct access to the socket variable that sends it. Whenever I send the DNS packet, wireshark says…

Element wise comparison between 1D and 2D array

Want to perform an element wise comparison between an 1D and 2D array. Each element of the 1D array need to be compared (e.g. greater) against the corresponding row of 2D and a mask will be created. He…

Jquery ajax post request not working

I have a simple form submission with ajax, but it keeps giving me an error. All the error says is "error". No code, no description. No nothing, when I alert it when it fails.Javascript with …