In this short guide, you'll see the difference between dot notation and square bracket notation in Python and Pandas.
Here you can find the short answer:
(1) Dot notation for attributes
df.column_name
obj.attribute
(2) Square bracket notation for keys
df['column_name']
dict['key']
(3) When you must use brackets
df['column name with spaces']
df['2024'] # Starts with number
So let's see when to use dot notation versus square bracket notation in Python.
Suppose you have a DataFrame like:
| Name | Age | Salary |
|---|---|---|
| Alice | 28 | 75000 |
| Bob | 35 | 85000 |
1: Dot notation - Simple attribute access
Let's start with dot notation, which provides clean and readable syntax for accessing object attributes and DataFrame columns:
import pandas as pd
df = pd.DataFrame({
'name': ['Apple Inc', 'Microsoft Corp', 'Google LLC'],
'revenue': [394000, 211000, 307000],
'employees': [164000, 221000, 190000]
})
print(df.name)
print(df.revenue.mean())
print(df.employees.max())
result will be:
0 Apple Inc
1 Microsoft Corp
2 Google LLC
Name: name, dtype: object
304000.0
221000
Dot notation is the preferred style when:
- Column names are valid Python identifiers (no spaces, don't start with numbers)
- You want cleaner, more readable code
- Using IDE autocomplete features
What if you try to use dot notation with invalid column names? You'll get an error:
df.Apple Inc # SyntaxError - spaces not allowed
df.2024_data # SyntaxError - starts with number
2: Square bracket notation - Universal access method
Square bracket notation is the universal method that works with any column name or dictionary key, regardless of naming conventions:
import pandas as pd
df = pd.DataFrame({
'Company Name': ['Amazon', 'Tesla', 'Meta'],
'2024 Revenue': [575000, 96000, 134000],
'Market Cap': [1800000, 850000, 950000],
'P/E Ratio': [45.2, 68.9, 28.4]
})
print(df['Company Name'])
print(f"Average 2024 Revenue: ${df['2024 Revenue'].mean():,.0f}")
print(f"Highest Market Cap: ${df['Market Cap'].max():,.0f}")
print(f"Average P/E: {df['P/E Ratio'].mean():.1f}")
result:
0 Amazon
1 Tesla
2 Meta
Name: Company Name, dtype: object
Average 2024 Revenue: $268,333
Highest Market Cap: $1,800,000
Average P/E: 47.5
Square bracket notation is required when:
- Column names contain spaces (
'Company Name') - Column names start with numbers (
'2024 Revenue') - Column names contain special characters (
'P/E Ratio') - Accessing dictionary keys with any string
- Column name stored in a variable
3: Working with dictionaries - Square brackets required
For Python dictionaries, you must use square bracket notation to access values:
company_data = {
'name': 'NVIDIA Corporation',
'ticker': 'NVDA',
'sector': 'Technology',
'market_cap': 1200000,
'52_week_high': 505.89
}
print(f"Company: {company_data['name']}")
print(f"Ticker: {company_data['ticker']}")
print(f"52-Week High: ${company_data['52_week_high']}")
try:
print(company_data.name)
except AttributeError as e:
print(f"Error with dot notation: {e}")
result:
Company: NVIDIA Corporation
Ticker: NVDA
52-Week High: $505.89
Error with dot notation: 'dict' object has no attribute 'name'
Key point: Standard Python dictionaries don't support dot notation. Only special objects like pandas DataFrames allow both syntaxes.
4: Dynamic column access with variables
Square bracket notation is essential when column names are stored in variables or generated dynamically:
import pandas as pd
df = pd.DataFrame({
'AAPL': [185.64, 186.89, 185.92],
'MSFT': [372.55, 375.23, 373.89],
'GOOGL': [145.23, 146.78, 145.67]
})
user_stock = 'AAPL'
print(f"{user_stock} prices:")
print(df[user_stock])
for ticker in ['AAPL', 'MSFT', 'GOOGL']:
avg_price = df[ticker].mean()
print(f"{ticker} average: ${avg_price:.2f}")
result:
AAPL prices:
0 185.64
1 186.89
2 185.92
Name: AAPL, dtype: float64
AAPL average: $186.15
MSFT average: $373.89
GOOGL average: $145.89
You cannot use dot notation with variables: df.user_stock would look for a column literally named "user_stock".
5: Pandas-specific considerations
Pandas DataFrames support both notations, but with important differences in behavior and method conflicts:
import pandas as pd
df = pd.DataFrame({
'product': ['iPhone 15', 'Galaxy S24', 'Pixel 8'],
'price': [999, 899, 699],
'count': [1000, 850, 650],
'sum': [999000, 764150, 454350]
})
print("Using dot notation:")
print(df.price.mean())
print("\nUsing square brackets:")
print(df['price'].mean())
print("\nConflict with DataFrame method 'count':")
print(type(df.count))
print(type(df['count']))
print("\nAccessing actual 'count' column:")
print(df['count'].head())
print("\nConflict with DataFrame method 'sum':")
try:
print(df.sum.mean())
except TypeError as e:
print(f"Error: {e}")
print("\nCorrect way:")
print(df['sum'].mean())
result:
Using dot notation:
865.6666666666666
Using square brackets:
865.6666666666666
Conflict with DataFrame method 'count':
<class 'method'>
<class 'pandas.core.series.Series'>
Accessing actual 'count' column:
0 1000
1 850
2 650
Name: count, dtype: int64
Conflict with DataFrame method 'sum':
Error: 'builtin_function_or_method' object has no attribute 'mean'
Correct way:
739166.6666666666667
Reserved pandas methods that conflict with column names:
count,sum,mean,max,min,std,varhead,tail,describe,info,shapeindex,columns,values,dtypessort,drop,merge,join,fillna
Best practice: Always use square bracket notation for columns that might conflict with pandas methods.
6: Creating new columns - Syntax differences
When creating new columns, both notations work, but square brackets are more reliable:
import pandas as pd
df = pd.DataFrame({
'company': ['Apple', 'Microsoft', 'Google'],
'revenue': [394000, 211000, 307000],
'expenses': [276000, 138000, 198000]
})
df['profit'] = df['revenue'] - df['expenses']
df.margin = (df['profit'] / df['revenue']) * 100
df['profit_margin'] = df.margin
print(df[['company', 'revenue', 'profit', 'profit_margin']])
result:
company revenue profit profit_margin
0 Apple 394000 118000 29.949239
1 Microsoft 211000 73000 34.597156
2 Google 307000 109000 35.504886
Warning: Creating columns with dot notation (df.new_col = ...) can sometimes create Python attributes instead of DataFrame columns, especially in certain contexts. Always use square brackets for column creation in production code.
7: Common errors and how to fix them
Understanding common errors helps avoid pitfalls when choosing between dot and bracket notation:
Error 1: AttributeError with dot notation
import pandas as pd
df = pd.DataFrame({
'Customer Name': ['Apple Inc', 'Microsoft Corp'],
'Order Value': [15000, 22000]
})
try:
print(df.Customer Name)
except SyntaxError:
print("SyntaxError: invalid syntax")
try:
print(df.customer_name)
except AttributeError as e:
print(f"AttributeError: {e}")
print("\nCorrect way:")
print(df['Customer Name'])
result:
SyntaxError: invalid syntax
AttributeError: 'DataFrame' object has no attribute 'customer_name'
Correct way:
0 Apple Inc
1 Microsoft Corp
Name: Customer Name, dtype: object
Error 2: KeyError with square brackets
import pandas as pd
df = pd.DataFrame({
'product': ['iPhone', 'iPad'],
'price': [999, 599]
})
try:
print(df['Product'])
except KeyError as e:
print(f"KeyError: {e}")
print("\nColumn names are case-sensitive:")
print(df.columns.tolist())
print("\nCorrect way:")
print(df['product'])
result:
KeyError: 'Product'
Column names are case-sensitive:
['product', 'price']
Correct way:
0 iPhone
1 iPad
Name: product, dtype: object
Error 3: Method confusion with dot notation
import pandas as pd
df = pd.DataFrame({
'name': ['Tesla', 'Rivian'],
'count': [500000, 50000],
'max': [1000000, 100000]
})
print("Trying to access 'count' column with dot notation:")
print(f"Type: {type(df.count)}")
print("\nCorrect way to access 'count' column:")
print(df['count'])
print("\nTrying to access 'max' column with dot notation:")
print(f"Type: {type(df.max)}")
print("\nCorrect way to access 'max' column:")
print(df['max'])
result:
Trying to access 'count' column with dot notation:
Type: <class 'method'>
Correct way to access 'count' column:
0 500000
1 50000
Name: count, dtype: int64
Trying to access 'max' column with dot notation:
Type: <class 'method'>
Correct way to access 'max' column:
0 1000000
1 100000
Name: max, dtype: int64
Error 4: Assignment confusion
import pandas as pd
df = pd.DataFrame({'value': [10, 20, 30]})
df.new_column_dot = [100, 200, 300]
df['new_column_bracket'] = [100, 200, 300]
print("DataFrame columns:")
print(df.columns.tolist())
print("\nDataFrame contents:")
print(df)
print("\nChecking if 'new_column_dot' is in DataFrame:")
print('new_column_dot' in df.columns)
print("\nIt became a DataFrame attribute instead:")
print(hasattr(df, 'new_column_dot'))
result:
DataFrame columns:
['value', 'new_column_bracket']
DataFrame contents:
value new_column_bracket
0 10 100
1 20 200
2 30 300
Checking if 'new_column_dot' is in DataFrame:
False
It became a DataFrame attribute instead:
True
Critical insight: Dot notation assignment creates Python attributes, not DataFrame columns. Always use square brackets to create new columns.
Comparison Table
| Feature | Dot Notation | Square Bracket |
|---|---|---|
| Syntax | df.column |
df['column'] |
| With spaces | ❌ Not allowed | ✅ Works |
| Starts with number | ❌ Not allowed | ✅ Works |
| Special characters | ❌ Not allowed | ✅ Works |
| Variables | ❌ Not supported | ✅ Supported |
| Method conflicts | ⚠️ Conflicts (count, sum, etc.) | ✅ No conflicts |
| Column creation | ⚠️ Creates attributes | ✅ Creates columns |
| Autocomplete | ✅ IDE support | ⚠️ Limited |
| Readability | ✅ Cleaner | ⚠️ More verbose |
| Dictionaries | ❌ Not supported | ✅ Required |
Best Practices
✅ Use square brackets in production code for reliability
✅ Use dot notation only for quick interactive analysis with simple column names
✅ Always use brackets when column names might conflict with pandas methods
✅ Always use brackets for column creation: df['new_col'] = ...
✅ Use brackets when column names might change or come from external sources
❌ Don't use dot notation for columns named after pandas methods
❌ Don't mix both styles inconsistently in the same codebase
❌ Avoid dot notation if column names aren't under your control
Common Use Cases
Data Analysis (dot notation - use with caution):
df.revenue.sum() # Only if 'revenue' won't conflict
df.price.mean()
df.quantity.describe()
Production Code (square brackets - always safe):
df['Revenue (USD)'].sum()
df['2024 Price'].mean()
df['Order Count'].max() # 'count' would conflict with df.count()
Dynamic Access (must use brackets):
metrics = ['revenue', 'profit', 'growth']
for metric in metrics:
print(df[metric].describe())
Column Creation (always use brackets):
df['total'] = df['price'] * df['quantity']
df['margin'] = (df['profit'] / df['revenue']) * 100