Explore the PyQGIS API with dir() and help()

The PyQGIS API is enormous, the documentation is generated from C++, and the method you need is frequently one word away from the one you guessed. Introspection closes that gap faster than searching: the object in front of you knows exactly what it can do, and three lines in the console will tell you.

This recipe belongs to QGIS API Architecture. It covers listing an object's methods, filtering the inherited Qt noise, reading the signature and docstring of a method, checking which class you actually have, and translating what you find into the online documentation.

Why dir() returns three hundred namesA vector layer object inherits from the QGIS map layer class, which inherits from the Qt object base class. Each level contributes methods. Most of what dir returns comes from the lower levels and from Python's own attributes, while the methods specific to vector layers are a comparatively small set at the top of the chain.Most of what you see is inherited, not what you are looking forQgsVectorLayergetFeatures, fields, startEditingQgsMapLayername, id, crs, extent, isValidQObject and Pythonsignals, properties, dunder nameswhat dir() gives youthe ones you want — a few dozeninherited layer methods — useful tooQt plumbing and dunder namesfilter these out first

Prerequisites

  • QGIS 3.34 LTR (bundled Python 3.12) or newer.
  • The Python console open — see QGIS Python Console Basics.
  • A loaded layer to experiment on, though any object will do.

List what an object can do

layer = iface.activeLayer()

methods = [name for name in dir(layer) if not name.startswith("_")]
print(len(methods))

print([name for name in methods if "field" in name.lower()])

Breakdown: dir() returns every attribute name the object exposes, including everything inherited from QgsMapLayer, QObject and Python itself — several hundred names, most of which are not what you want. Dropping names beginning with an underscore removes Python's internals immediately. The substring filter is the part that does the real work: you rarely know the exact method name, but you almost always know a word that will be in it. Searching for field, crs, select or commit narrows three hundred names to five in one line, and the answer is usually obvious from the list.

Read the signature and the documentation

help(layer.getFeatures)

help(QgsVectorLayer.setSubsetString)

Breakdown: help() on a bound method prints the signature and whatever docstring the bindings carry, which for PyQGIS is generated from the C++ header and includes the parameter and return types. Those types are the most valuable part: seeing that getFeatures() accepts a QgsFeatureRequest tells you where to look next far more directly than any tutorial. Calling help() on the class rather than an instance works identically and is handy when you have no object to hand. Where a method is overloaded — common in Qt-derived classes — you get every signature listed, which explains why a call that "should" work fails: you matched a different overload than you thought.

For a compact view in the console, signature from the standard library is often easier to read:

import inspect

print(inspect.signature(QgsVectorLayer.setSubsetString))

Breakdown: inspect.signature() gives one line rather than a page. It works for most PyQGIS bindings, and raises ValueError for the few built entirely in C++ without introspection metadata — in which case fall back to help(), which always has something to show.

Find out what you are actually holding

Half of all PyQGIS confusion is having a different class than you assumed.

print(type(layer))
print(type(layer).__mro__)
print(layer.__class__.__name__)

from qgis.core import QgsVectorLayer
print(isinstance(layer, QgsVectorLayer))

Breakdown: type() names the exact class, and the method resolution order shows the whole inheritance chain — which is how you discover that a QgsVectorLayer is a QgsMapLayer and therefore has everything documented on that page too. isinstance() is the right check in real code, because it accepts subclasses; comparing type(layer) == QgsVectorLayer fails for anything derived. This is also the fastest way to diagnose the classic "AttributeError on a valid layer" — the object is a QgsRasterLayer, or None, and the missing method was never going to be there.

Four questions, four one-linersTo ask what an object can do, use dir with a substring filter. To ask how a method is called, use help or inspect signature. To ask what class an object is, use type and the method resolution order. To ask what an enumeration value means, print the enumeration members from the class. Each row pairs the question with the exact call.Match the question to the callwhat you are askingwhat to typewhat can this object do?dir(obj) with a substring filterhow is this method called?help(obj.method) or inspect.signaturewhat class is this really?type(obj) and type(obj).mrowhat does this number mean?list the enum members on the class

Decode enumerations and constants

Many PyQGIS calls take or return integer-backed enumeration values, and a bare 2 in the console tells you nothing.

from qgis.core import QgsWkbTypes, Qgis

print(QgsWkbTypes.displayString(layer.wkbType()))

print([name for name in dir(Qgis.GeometryType) if not name.startswith("_")])
print(int(Qgis.GeometryType.Polygon), Qgis.GeometryType.Polygon.name)

Breakdown: Several QGIS enumerations ship a helper that turns a value into readable text — QgsWkbTypes.displayString() is the one you will use most, turning an opaque geometry type code into MultiPolygon. For the newer scoped enumerations under Qgis, listing the members shows every legal value, and each member has a name, which makes log messages readable. Printing the integer alongside is occasionally necessary when comparing against a value read from a file or a database column.

Map what you found onto the documentation

Introspection tells you a method exists; the API documentation tells you what it means. Two habits connect them.

Search the class, not the method. The QGIS API documentation is organised by class, and the class name from type() takes you straight to the page listing every method with its full C++ signature and, usually, a paragraph of explanation. Inherited members are on a separate tab, which is why the method resolution order is worth knowing.

Read the C++ types as Python ones. QString is str, QList<QgsFeature> is a Python list of features, a bool *ok output parameter usually becomes an extra value in a returned tuple, and a method documented as returning void returns None. Once that translation is automatic, the C++ documentation reads as Python documentation.

Reading C++ signatures as PythonA QString becomes a Python string. A list of features becomes a Python list. An output boolean pointer usually becomes an extra value in a returned tuple. A void return becomes None. A const reference is simply a value. Learning these five equivalences makes the generated documentation readable without translation.Five equivalences and the documentation reads as Pythonwhat the documentation sayswhat you writeQString namean ordinary strQList of QgsFeaturea Python list of featuresbool ok output parameteran extra value in the returned tuplevoidreturns None

The one place introspection cannot help is behaviour: whether a method commits immediately, whether it invalidates an iterator, whether it is safe on a background thread. That is what the documentation and the wider guides here are for — QGIS API Architecture covers how the modules fit together, and QGIS Python Version Compatibility Guide covers what changed between releases.

QGIS version compatibility

QGIS versionPythonNotes
3.22 LTR3.9dir(), help() and inspect behave identically; some scoped enumerations under Qgis do not yet exist.
3.28 LTR3.9Identical.
3.34 LTR3.12Baseline for this page; most enumerations available in both the legacy and scoped forms.
3.40 / 3.443.12Legacy enumeration aliases are being removed release by release — check with dir() rather than assuming an old name survives.

Introspection is also the fastest way to handle a version difference: hasattr(layer, "someNewMethod") is a one-line compatibility check that keeps a plugin working across releases.

Troubleshooting

  • dir() returns hundreds of names. Filter by substring; almost nobody reads the full list.
  • help() shows only the signature. The binding carries no docstring for that method. The class page in the API documentation will have the prose.
  • inspect.signature() raises ValueError. A pure C++ binding without introspection metadata. Use help().
  • A method exists but raises TypeError when called. You matched a different overload. help() lists them all; check the argument types.
  • An attribute is missing on an object that should have it. Check type() — it is very often None, a raster layer, or a layer tree node rather than the layer itself.
  • A name from a tutorial does not exist. It is QGIS 2 code, or a renamed method. Search dir() for a distinctive word from the old name.

Conclusion

Three calls cover most exploration: dir() with a substring filter to find candidate methods, help() or inspect.signature() to learn how to call one, and type() with the method resolution order to confirm what you are holding. Decode enumerations with their display helpers, and use the class name to jump into the API documentation for the behaviour introspection cannot show you.

Frequently Asked Questions

Is the console's autocomplete the same thing? It is dir() with a nicer interface, and it is often quicker. Introspection in code still matters for compatibility checks and for exploring objects you cannot easily type a name for.

Why do method names look like Qt rather than Python? PyQGIS wraps a C++ API, so it keeps camel-case names and Qt conventions. It is not idiomatic Python and trying to guess snake-case equivalents will not work.

How do I list the signals an object emits? Filter dir() for names that are not callable methods, or check the class page in the documentation — signals are listed separately there. Connecting to one is covered in Connect Layer Signals in PyQGIS.

Can I introspect Processing algorithms this way? Their parameters are described by their own metadata rather than by Python attributes. Use the Processing tools described in Run a Processing Algorithm from a Script.

Does this work in a standalone script? Yes, identically — introspection needs nothing but the objects, so it works in a headless run as well as in the console.

Is there a faster way to find a class I only half remember the name of? Filter the module rather than an object: [n for n in dir(qgis.core) if "renderer" in n.lower()] lists every core class with that word in its name, which usually surfaces the one you meant in a single line. The same trick on qgis.gui and qgis.analysis covers the rest of the API, and it is considerably quicker than searching documentation for a name you cannot spell.

Can I see the source of a PyQGIS method? Rarely — most of it is compiled C++ with no Python source to show, so inspect.getsource() raises. Pure-Python parts of QGIS, such as the Processing framework and the plugin installer, do return their source, which makes them worth reading when you want to see how the framework itself calls the API.