opencode-skills-collection 3.0.49 → 3.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +27 -1
- package/bundled-skills/ab-test-setup/SKILL.md +14 -0
- package/bundled-skills/apple-notes-search/SKILL.md +122 -0
- package/bundled-skills/astropy/references/coordinates.md +9 -0
- package/bundled-skills/astropy/references/cosmology.md +8 -0
- package/bundled-skills/astropy/references/fits.md +8 -0
- package/bundled-skills/astropy/references/tables.md +8 -0
- package/bundled-skills/astropy/references/time.md +7 -0
- package/bundled-skills/astropy/references/units.md +9 -0
- package/bundled-skills/astropy/references/wcs_and_other_modules.md +9 -0
- package/bundled-skills/browser-extension-builder/SKILL.md +1 -1
- package/bundled-skills/ckw-design/SKILL.md +129 -0
- package/bundled-skills/deterministic-design/SKILL.md +56 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/lint-and-validate/SKILL.md +3 -1
- package/bundled-skills/lookdev/SKILL.md +229 -0
- package/bundled-skills/lookdev-auto/SKILL.md +102 -0
- package/bundled-skills/macos-screen-recorder/SKILL.md +59 -0
- package/bundled-skills/pr-merge-champion/SKILL.md +116 -0
- package/bundled-skills/programmatic-seo/SKILL.md +11 -0
- package/bundled-skills/schema-markup/SKILL.md +11 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +91 -0
- package/bundled-skills/super-code/SKILL.md +209 -0
- package/bundled-skills/super-code/bash/SKILL.md +292 -0
- package/bundled-skills/super-code/c/SKILL.md +263 -0
- package/bundled-skills/super-code/cpp/SKILL.md +271 -0
- package/bundled-skills/super-code/csharp/SKILL.md +276 -0
- package/bundled-skills/super-code/dart/SKILL.md +327 -0
- package/bundled-skills/super-code/elixir/SKILL.md +366 -0
- package/bundled-skills/super-code/go/SKILL.md +234 -0
- package/bundled-skills/super-code/java/SKILL.md +230 -0
- package/bundled-skills/super-code/kotlin/SKILL.md +281 -0
- package/bundled-skills/super-code/php/SKILL.md +316 -0
- package/bundled-skills/super-code/python/SKILL.md +315 -0
- package/bundled-skills/super-code/ruby/SKILL.md +306 -0
- package/bundled-skills/super-code/rust/SKILL.md +289 -0
- package/bundled-skills/super-code/scala/SKILL.md +302 -0
- package/bundled-skills/super-code/swift/SKILL.md +299 -0
- package/bundled-skills/super-code/typescript/SKILL.md +286 -0
- package/bundled-skills/web-media-getter/SKILL.md +119 -0
- package/bundled-skills/youtube-seo-optimizer/SKILL.md +9 -9
- package/package.json +1 -1
- package/skills_index.json +574 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: php
|
|
3
|
+
description: "Language-specific super-code guidelines for php."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# PHP: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Arrays & Collections](#arrays)
|
|
12
|
+
2. [Type Safety](#types)
|
|
13
|
+
3. [Error Handling](#errors)
|
|
14
|
+
4. [String Handling](#strings)
|
|
15
|
+
5. [OOP & Modern PHP](#oop)
|
|
16
|
+
6. [Functions & Closures](#functions)
|
|
17
|
+
7. [Anti-patterns specific to PHP](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Arrays & Collections {#arrays}
|
|
22
|
+
|
|
23
|
+
```php
|
|
24
|
+
// ❌ Manual accumulation
|
|
25
|
+
$result = [];
|
|
26
|
+
foreach ($items as $item) {
|
|
27
|
+
if ($item->isActive()) {
|
|
28
|
+
$result[] = strtoupper($item->getName());
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ✅
|
|
33
|
+
$result = array_map(
|
|
34
|
+
fn($i) => strtoupper($i->getName()),
|
|
35
|
+
array_filter($items, fn($i) => $i->isActive())
|
|
36
|
+
);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```php
|
|
40
|
+
// ❌ Manual key-value grouping
|
|
41
|
+
$grouped = [];
|
|
42
|
+
foreach ($items as $item) {
|
|
43
|
+
$grouped[$item->getCategory()][] = $item;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ✅ (PHP 8.1+) — or use the loop above; PHP lacks a built-in groupBy
|
|
47
|
+
// The foreach is actually idiomatic PHP for grouping. No need to force array_* here.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```php
|
|
51
|
+
// ❌ Checking isset then accessing
|
|
52
|
+
if (isset($data['key'])) {
|
|
53
|
+
$value = $data['key'];
|
|
54
|
+
} else {
|
|
55
|
+
$value = 'default';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ✅
|
|
59
|
+
$value = $data['key'] ?? 'default';
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```php
|
|
63
|
+
// ❌ array_push for single element
|
|
64
|
+
array_push($items, $newItem);
|
|
65
|
+
|
|
66
|
+
// ✅
|
|
67
|
+
$items[] = $newItem;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Use `array_map`/`array_filter` for transforms. The `foreach` loop is fine when array functions would be less readable.**
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2. Type Safety {#types}
|
|
75
|
+
|
|
76
|
+
```php
|
|
77
|
+
// ❌ No type declarations
|
|
78
|
+
function process($items) {
|
|
79
|
+
return $items;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ✅ (PHP 8.0+)
|
|
83
|
+
function process(array $items): array {
|
|
84
|
+
return $items;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```php
|
|
89
|
+
// ❌ Union type for nullable
|
|
90
|
+
function find(string $key): string|null { ... }
|
|
91
|
+
|
|
92
|
+
// ✅
|
|
93
|
+
function find(string $key): ?string { ... }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```php
|
|
97
|
+
// ❌ Loose comparison
|
|
98
|
+
if ($value == '0') { ... } // true for 0, '', false, null
|
|
99
|
+
|
|
100
|
+
// ✅
|
|
101
|
+
if ($value === '0') { ... }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```php
|
|
105
|
+
// ❌ Type checking with gettype()
|
|
106
|
+
if (gettype($x) === 'integer') { ... }
|
|
107
|
+
|
|
108
|
+
// ✅
|
|
109
|
+
if (is_int($x)) { ... }
|
|
110
|
+
// or with union types, avoid checks entirely
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Enable `declare(strict_types=1)` at the top of every file.**
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 3. Error Handling {#errors}
|
|
118
|
+
|
|
119
|
+
```php
|
|
120
|
+
// ❌ Suppressing errors with @
|
|
121
|
+
$data = @file_get_contents($path);
|
|
122
|
+
|
|
123
|
+
// ✅
|
|
124
|
+
$data = file_get_contents($path);
|
|
125
|
+
if ($data === false) {
|
|
126
|
+
throw new RuntimeException("Failed to read: $path");
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```php
|
|
131
|
+
// ❌ Catching \Exception and swallowing
|
|
132
|
+
try { process(); }
|
|
133
|
+
catch (\Exception $e) { /* silence */ }
|
|
134
|
+
|
|
135
|
+
// ✅
|
|
136
|
+
try {
|
|
137
|
+
process();
|
|
138
|
+
} catch (SpecificException $e) {
|
|
139
|
+
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
|
140
|
+
throw new AppException('Processing failed', previous: $e);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```php
|
|
145
|
+
// ❌ Returning mixed types for error indication
|
|
146
|
+
function divide(int $a, int $b): int|false {
|
|
147
|
+
if ($b === 0) return false;
|
|
148
|
+
return intdiv($a, $b);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ✅ — throw exception for exceptional cases
|
|
152
|
+
function divide(int $a, int $b): int {
|
|
153
|
+
if ($b === 0) throw new \DivisionByZeroError();
|
|
154
|
+
return intdiv($a, $b);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 4. String Handling {#strings}
|
|
161
|
+
|
|
162
|
+
```php
|
|
163
|
+
// ❌ Concatenation for variable interpolation
|
|
164
|
+
$msg = 'Hello, ' . $name . '! You have ' . $count . ' messages.';
|
|
165
|
+
|
|
166
|
+
// ✅
|
|
167
|
+
$msg = "Hello, {$name}! You have {$count} messages.";
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```php
|
|
171
|
+
// ❌ Manual string contains check
|
|
172
|
+
if (strpos($haystack, $needle) !== false) { ... }
|
|
173
|
+
|
|
174
|
+
// ✅ (PHP 8.0+)
|
|
175
|
+
if (str_contains($haystack, $needle)) { ... }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```php
|
|
179
|
+
// ❌ substr for prefix/suffix check
|
|
180
|
+
if (substr($str, 0, 4) === 'http') { ... }
|
|
181
|
+
if (substr($str, -4) === '.php') { ... }
|
|
182
|
+
|
|
183
|
+
// ✅ (PHP 8.0+)
|
|
184
|
+
if (str_starts_with($str, 'http')) { ... }
|
|
185
|
+
if (str_ends_with($str, '.php')) { ... }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 5. OOP & Modern PHP {#oop}
|
|
191
|
+
|
|
192
|
+
```php
|
|
193
|
+
// ❌ Manual constructor property assignment
|
|
194
|
+
class User {
|
|
195
|
+
private string $name;
|
|
196
|
+
private int $age;
|
|
197
|
+
public function __construct(string $name, int $age) {
|
|
198
|
+
$this->name = $name;
|
|
199
|
+
$this->age = $age;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ✅ (PHP 8.0+)
|
|
204
|
+
class User {
|
|
205
|
+
public function __construct(
|
|
206
|
+
private readonly string $name,
|
|
207
|
+
private readonly int $age,
|
|
208
|
+
) {}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```php
|
|
213
|
+
// ❌ Constants as class properties
|
|
214
|
+
class Status {
|
|
215
|
+
const ACTIVE = 'active';
|
|
216
|
+
const INACTIVE = 'inactive';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ✅ (PHP 8.1+)
|
|
220
|
+
enum Status: string {
|
|
221
|
+
case Active = 'active';
|
|
222
|
+
case Inactive = 'inactive';
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```php
|
|
227
|
+
// ❌ instanceof chains
|
|
228
|
+
if ($shape instanceof Circle) { ... }
|
|
229
|
+
elseif ($shape instanceof Rectangle) { ... }
|
|
230
|
+
|
|
231
|
+
// ✅ (PHP 8.0+)
|
|
232
|
+
$area = match(true) {
|
|
233
|
+
$shape instanceof Circle => $shape->radius ** 2 * M_PI,
|
|
234
|
+
$shape instanceof Rectangle => $shape->width * $shape->height,
|
|
235
|
+
default => throw new \InvalidArgumentException("Unknown shape"),
|
|
236
|
+
};
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```php
|
|
240
|
+
// ❌ Named constructor via static method returning new self()
|
|
241
|
+
class Money {
|
|
242
|
+
public static function fromCents(int $cents): self {
|
|
243
|
+
$m = new self();
|
|
244
|
+
$m->cents = $cents;
|
|
245
|
+
return $m;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ✅ (PHP 8.0+) — constructor promotion + named arguments
|
|
250
|
+
class Money {
|
|
251
|
+
public function __construct(
|
|
252
|
+
public readonly int $cents,
|
|
253
|
+
) {}
|
|
254
|
+
}
|
|
255
|
+
$m = new Money(cents: 500);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 6. Functions & Closures {#functions}
|
|
261
|
+
|
|
262
|
+
```php
|
|
263
|
+
// ❌ Verbose closure for simple operation
|
|
264
|
+
$doubled = array_map(function ($x) { return $x * 2; }, $numbers);
|
|
265
|
+
|
|
266
|
+
// ✅ (PHP 7.4+)
|
|
267
|
+
$doubled = array_map(fn($x) => $x * 2, $numbers);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```php
|
|
271
|
+
// ❌ Passing globals or using `global` keyword
|
|
272
|
+
global $db;
|
|
273
|
+
function getUser(int $id) {
|
|
274
|
+
global $db;
|
|
275
|
+
return $db->find($id);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ✅ — dependency injection
|
|
279
|
+
function getUser(int $id, PDO $db): ?User {
|
|
280
|
+
return $db->find($id);
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
```php
|
|
285
|
+
// ❌ Named arguments abused for every call
|
|
286
|
+
str_pad(string: $s, length: 10, pad_string: ' ', pad_type: STR_PAD_LEFT);
|
|
287
|
+
|
|
288
|
+
// ✅ — named args are useful for readability on ambiguous params; don't force
|
|
289
|
+
str_pad($s, 10, ' ', STR_PAD_LEFT);
|
|
290
|
+
// but named args shine for: new User(name: 'Alice', age: 30)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## 7. Anti-patterns specific to PHP {#antipatterns}
|
|
296
|
+
|
|
297
|
+
| Anti-pattern | Preferred |
|
|
298
|
+
|---|---|
|
|
299
|
+
| `==` for comparison | `===` (strict equality) |
|
|
300
|
+
| `@` error suppression | explicit error handling |
|
|
301
|
+
| `global` keyword | dependency injection |
|
|
302
|
+
| `extract()` on user input | access keys explicitly |
|
|
303
|
+
| `die()` / `exit()` in library code | throw exception |
|
|
304
|
+
| `strpos !== false` for contains | `str_contains()` (PHP 8.0) |
|
|
305
|
+
| Manual constructor assignment | constructor promotion (PHP 8.0) |
|
|
306
|
+
| Class constants for enums | `enum` (PHP 8.1) |
|
|
307
|
+
| `mixed` return types | specific typed returns |
|
|
308
|
+
| `array` for everything | typed classes / DTOs |
|
|
309
|
+
| `var_dump` / `print_r` debugging | proper logging (PSR-3) |
|
|
310
|
+
| Not using `declare(strict_types=1)` | always enable |
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
## Limitations
|
|
315
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
316
|
+
- Over-compression might reduce readability; apply judgement.
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: "Language-specific super-code guidelines for python."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Python: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Comprehensions & Generators](#comprehensions)
|
|
12
|
+
2. [Unpacking & Destructuring](#unpacking)
|
|
13
|
+
3. [Built-ins & stdlib](#builtins)
|
|
14
|
+
4. [Functions & Defaults](#functions)
|
|
15
|
+
5. [Classes & Dataclasses](#classes)
|
|
16
|
+
6. [Error Handling](#errors)
|
|
17
|
+
7. [Type Hints](#types)
|
|
18
|
+
8. [Anti-patterns specific to Python](#antipatterns)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. Comprehensions & Generators {#comprehensions}
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
# ❌ Imperative accumulation
|
|
26
|
+
result = []
|
|
27
|
+
for item in items:
|
|
28
|
+
if item.active:
|
|
29
|
+
result.append(item.name.upper())
|
|
30
|
+
|
|
31
|
+
# ✅
|
|
32
|
+
result = [item.name.upper() for item in items if item.active]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# ❌ Dict built in a loop
|
|
37
|
+
d = {}
|
|
38
|
+
for k, v in pairs:
|
|
39
|
+
d[k] = v
|
|
40
|
+
|
|
41
|
+
# ✅
|
|
42
|
+
d = dict(pairs)
|
|
43
|
+
# or
|
|
44
|
+
d = {k: v for k, v in pairs}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
# ❌ Generator converted to list unnecessarily
|
|
49
|
+
total = sum(list(x * 2 for x in nums))
|
|
50
|
+
|
|
51
|
+
# ✅ — generator expression works directly in sum()
|
|
52
|
+
total = sum(x * 2 for x in nums)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Use generator expressions (not list comprehensions) when the result is consumed once and not stored.**
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 2. Unpacking & Destructuring {#unpacking}
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
# ❌ Index access
|
|
63
|
+
first = items[0]
|
|
64
|
+
rest = items[1:]
|
|
65
|
+
|
|
66
|
+
# ✅
|
|
67
|
+
first, *rest = items
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# ❌ Temporary variable for swap
|
|
72
|
+
tmp = a
|
|
73
|
+
a = b
|
|
74
|
+
b = tmp
|
|
75
|
+
|
|
76
|
+
# ✅
|
|
77
|
+
a, b = b, a
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# ❌ items() with separate indexing
|
|
82
|
+
for i in range(len(items)):
|
|
83
|
+
print(i, items[i])
|
|
84
|
+
|
|
85
|
+
# ✅
|
|
86
|
+
for i, item in enumerate(items):
|
|
87
|
+
print(i, item)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# ❌ zip with separate index
|
|
92
|
+
for i in range(len(a)):
|
|
93
|
+
process(a[i], b[i])
|
|
94
|
+
|
|
95
|
+
# ✅
|
|
96
|
+
for x, y in zip(a, b):
|
|
97
|
+
process(x, y)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 3. Built-ins & stdlib {#builtins}
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# ❌ Manual max search
|
|
106
|
+
max_val = items[0]
|
|
107
|
+
for item in items[1:]:
|
|
108
|
+
if item > max_val:
|
|
109
|
+
max_val = item
|
|
110
|
+
|
|
111
|
+
# ✅
|
|
112
|
+
max_val = max(items)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
# ❌ Manual grouping
|
|
117
|
+
from collections import defaultdict
|
|
118
|
+
groups = defaultdict(list)
|
|
119
|
+
for item in items:
|
|
120
|
+
groups[item.category].append(item)
|
|
121
|
+
|
|
122
|
+
# ✅ — same thing, just be explicit about defaultdict; it IS the right tool
|
|
123
|
+
# (this example is already correct — don't replace defaultdict with a loop)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# ❌ Manual sentinel for dict default
|
|
128
|
+
if key in d:
|
|
129
|
+
val = d[key]
|
|
130
|
+
else:
|
|
131
|
+
val = default
|
|
132
|
+
|
|
133
|
+
# ✅
|
|
134
|
+
val = d.get(key, default)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
# ❌ Rolling your own counter
|
|
139
|
+
counts = {}
|
|
140
|
+
for item in items:
|
|
141
|
+
counts[item] = counts.get(item, 0) + 1
|
|
142
|
+
|
|
143
|
+
# ✅
|
|
144
|
+
from collections import Counter
|
|
145
|
+
counts = Counter(items)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Use `itertools` (chain, islice, groupby, product) before writing nested loops for combinatorial or streaming logic.**
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 4. Functions & Defaults {#functions}
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
# ❌ Mutable default argument (bug, not just style)
|
|
156
|
+
def append_to(item, lst=[]):
|
|
157
|
+
lst.append(item)
|
|
158
|
+
return lst
|
|
159
|
+
|
|
160
|
+
# ✅
|
|
161
|
+
def append_to(item, lst=None):
|
|
162
|
+
if lst is None:
|
|
163
|
+
lst = []
|
|
164
|
+
lst.append(item)
|
|
165
|
+
return lst
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# ❌ Positional args for everything when keyword clarity helps
|
|
170
|
+
create_user("Alice", True, False, 30)
|
|
171
|
+
|
|
172
|
+
# ✅ — use keyword args at call site for boolean/ambiguous params
|
|
173
|
+
create_user("Alice", is_admin=True, is_active=False, age=30)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
# ❌ Long function doing multiple things
|
|
178
|
+
def process_and_save(data):
|
|
179
|
+
# 40 lines of transform
|
|
180
|
+
# 20 lines of DB write
|
|
181
|
+
...
|
|
182
|
+
|
|
183
|
+
# ✅ — split only if each part is reused OR independently testable
|
|
184
|
+
def _transform(data): ...
|
|
185
|
+
def _save(record): ...
|
|
186
|
+
def process_and_save(data): _save(_transform(data))
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 5. Classes & Dataclasses {#classes}
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
# ❌ Manual __init__ for data holders
|
|
195
|
+
class Point:
|
|
196
|
+
def __init__(self, x, y):
|
|
197
|
+
self.x = x
|
|
198
|
+
self.y = y
|
|
199
|
+
|
|
200
|
+
# ✅
|
|
201
|
+
from dataclasses import dataclass
|
|
202
|
+
|
|
203
|
+
@dataclass
|
|
204
|
+
class Point:
|
|
205
|
+
x: float
|
|
206
|
+
y: float
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
# ❌ Class just to hold a namespace of functions
|
|
211
|
+
class MathUtils:
|
|
212
|
+
@staticmethod
|
|
213
|
+
def add(a, b): return a + b
|
|
214
|
+
|
|
215
|
+
# ✅ — module-level functions; classes for state + behavior
|
|
216
|
+
def add(a, b): return a + b
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
# ❌ __repr__ written manually when dataclass gives it free
|
|
221
|
+
# (see above — use @dataclass)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Use `@dataclass(frozen=True)` for immutable value objects. Use `NamedTuple` when you need tuple unpacking.**
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 6. Error Handling {#errors}
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# ❌ Bare except
|
|
232
|
+
try:
|
|
233
|
+
risky()
|
|
234
|
+
except:
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
# ✅ — catch the specific exception; don't swallow silently
|
|
238
|
+
try:
|
|
239
|
+
risky()
|
|
240
|
+
except ValueError as e:
|
|
241
|
+
logger.warning("Invalid value: %s", e)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# ❌ LBYL (look before you leap) when EAFP is cleaner
|
|
246
|
+
if os.path.exists(path):
|
|
247
|
+
with open(path) as f:
|
|
248
|
+
data = f.read()
|
|
249
|
+
|
|
250
|
+
# ✅ (EAFP)
|
|
251
|
+
try:
|
|
252
|
+
with open(path) as f:
|
|
253
|
+
data = f.read()
|
|
254
|
+
except FileNotFoundError:
|
|
255
|
+
data = None
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
# ❌ Re-raising with raise e (loses traceback)
|
|
260
|
+
except Exception as e:
|
|
261
|
+
raise e
|
|
262
|
+
|
|
263
|
+
# ✅
|
|
264
|
+
except Exception:
|
|
265
|
+
raise # bare raise preserves original traceback
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 7. Type Hints {#types}
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
# ❌ Overly verbose Union syntax (Python <3.10 style in new code)
|
|
274
|
+
from typing import Optional, Union
|
|
275
|
+
def f(x: Optional[int]) -> Union[str, None]: ...
|
|
276
|
+
|
|
277
|
+
# ✅ (Python 3.10+)
|
|
278
|
+
def f(x: int | None) -> str | None: ...
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
# ❌ Any where a TypeVar or Protocol would be informative
|
|
283
|
+
from typing import Any
|
|
284
|
+
def first(lst: list[Any]) -> Any: ...
|
|
285
|
+
|
|
286
|
+
# ✅
|
|
287
|
+
from typing import TypeVar
|
|
288
|
+
T = TypeVar("T")
|
|
289
|
+
def first(lst: list[T]) -> T: ...
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Don't add type hints to every local variable — annotate function signatures and class fields; leave obvious locals inferred.**
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 8. Anti-patterns specific to Python {#antipatterns}
|
|
297
|
+
|
|
298
|
+
| Anti-pattern | Preferred |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `len(lst) == 0` | `not lst` |
|
|
301
|
+
| `if x == True:` | `if x:` |
|
|
302
|
+
| `if x == None:` | `if x is None:` |
|
|
303
|
+
| `range(len(lst))` for iteration | `enumerate(lst)` |
|
|
304
|
+
| String concatenation in a loop | `"".join(parts)` |
|
|
305
|
+
| `import *` | explicit imports |
|
|
306
|
+
| Catching `Exception` to log and re-raise | bare `raise` or let it propagate |
|
|
307
|
+
| `print()` for debug output | `logging.debug()` |
|
|
308
|
+
| `os.path.join` (Python 3.4+) | `pathlib.Path / "subpath"` |
|
|
309
|
+
| Manual `__eq__` + `__hash__` on value objects | `@dataclass(eq=True, frozen=True)` |
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
## Limitations
|
|
314
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
315
|
+
- Over-compression might reduce readability; apply judgement.
|