Skip to content

Instantly share code, notes, and snippets.

@xxleyi
Last active June 17, 2019 01:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xxleyi/8547c07b0ab63f33c0defe85069ef45b to your computer and use it in GitHub Desktop.
Save xxleyi/8547c07b0ab63f33c0defe85069ef45b to your computer and use it in GitHub Desktop.
整理代码风格,并聚集一些短小精悍的代码实例

用代码说话。

@xxleyi
Copy link
Author

xxleyi commented Jun 16, 2019

python - Rewrite to dictionary comprehensions - Stack Overflow

word = "aabcd"
occurrence = {}
for l in word.lower():
    if l in occurrence:
        occurrence[l] += 1
    else:
        occurrence[l] = 1

优化一下:

word = "aabcd"
occurrence = {}
for l in word.lower():
    occurrence[l] = (occurrence[l] if l in occurrence else 0) + 1

再优化一下:

word = "aabcd"
occurrence = {}
for l in word.lower():
    occurrence[l] = occurrence.setdefault(l, 0) + 1

最好的方式:

from collections import Counter
occurrence = Counter(word.lower())

@xxleyi
Copy link
Author

xxleyi commented Jun 16, 2019

python - How do I create a Subclass of the "list" class, that sorts itself upon instantiation? - Stack Overflow

accepted version:

class SortedList(list):
    def __init__(self, values):
        super().__init__(sorted(values))

x = SortedList([1, 9, 7])
print(x)

my version:

class SortedList(list):
    def __init__(self, values):
        super().__init__(values)
        super().sort()

x = SortedList([1, 3, 2])
print(x)

自觉我的版本更优雅 :-)

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Swap Values

In other languages:

temp = a 
a = b 
b = temp 

In Python:

b, a = a, b 

Perhaps you've seen this before. But do you know how it works?

  • The comma is the tuple constructor syntax.
  • A tuple is created on the right (tuple packing).
  • A tuple is the target on the left (tuple unpacking).

The right-hand side is unpacked into the names in the tuple on the left-hand side.

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Use in where possible (2)

But .keys() is necessary when mutating the dictionary:

for key in list(d.keys()): 
    d[str(key)] = d[key] 

list(d.keys()) creates a static list of the dictionary keys. Otherwise, you'll get an exception "RuntimeError: dictionary changed size during iteration".

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Dictionary setdefault Method (1)

Here we have to initialize mutable dictionary values. Each dictionary value will be a list. This is the naïve way:

Initializing mutable dictionary values:

equities = {}
for (portfolio, equity) in data:
    if portfolio in equities:
        equities[portfolio].append(equity)
    else:
        equities[portfolio] = [equity]

dict.setdefault(key, default) does the job much more efficiently:

equities = {}
for (portfolio, equity) in data:
    equities.setdefault(portfolio, []).append(equity)

dict.setdefault() is equivalent to "get, or set & get". Or "set if necessary, then get". It's especially efficient if your dictionary key is expensive to compute or long to type.

The only problem with dict.setdefault() is that the default value is always evaluated, whether needed or not. That only matters if the default value is expensive to compute.

If the default value is expensive to compute, you may want to use the defaultdict class, which we'll cover shortly.

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Dictionary setdefault Method (2)

Here we see that the setdefault dictionary method can also be used as a stand-alone statement:

setdefault can also be used as a stand-alone statement:

navs = {}
for (portfolio, equity, position) in data:
    navs.setdefault(portfolio, 0)
    navs[portfolio] += position * prices[equity]

The setdefault dictionary method returns the default value, but we ignore it here. We're taking advantage of setdefault's side effect, that it sets the dictionary value only if there is no value already.

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

from collections import defaultdict

equities = defaultdict(list)
for (portfolio, equity) in data:
    equities[portfolio].append(equity)

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

given = ['John', 'Eric', 'Terry', 'Michael']
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']
pythons = dict(zip(given, family))

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

# do this:        # not this:
if x:             if x == True:
    pass              pass 

# do this:        # not this:
if items:         if len(items) != 0:
    pass              pass

                  # and definitely not this:
                  if items != []:
                      pass

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Truth Values

The True and False names are built-in instances of type bool, Boolean values. Like None, there is only one instance of each.

False True

False (== 0)
True (== 1)

"" (empty string)
any string but "" (" ""anything")

00.0
any number but 0 (1, 0.1, -1, 3.14)

[](){}set()
any non-empty container ([0](None,)[''])

None
almost any object that's not explicitly False

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

>>> items = 'zero one two three'.split()
>>> print items
['zero', 'one', 'two', 'three']

                   - or -
i = 0
for item in items:      for i in range(len(items)):
    print i, item               print i, items[i]
    i += 1 

for (index, item) in enumerate(items):
    print index, item

# compare:              # compare:
index = 0               for i in range(len(items)):
for item in items:              print i, items[i]
    print index, item
    index += 1

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Default Parameter Values

This is a common mistake that beginners often make. Even more advanced programmers make this mistake if they don't understand Python names.

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Rule of thumb:

  • Use a list comprehension when a computed list is the desired end result.
  • Use a generator expression when the computed list is just an intermediate step.

Here's a recent example I saw at work.

We needed a dictionary mapping month numbers (both as string and as integers) to month codes for futures contracts. It can be done in one logical line of code.

The way this works is as follows:

  • The dict() built-in takes a list of key/value pairs (2-tuples).
  • We have a list of month codes (each month code is a single letter, and a string is also just a list of letters). We enumerate over this list to get both the month code and the index.
  • The month numbers start at 1, but Python starts indexing at 0, so the month number is one more than the index.
  • We want to look up months both as strings and as integers. We can use the int() and str() functions to do this for us, and loop over them.

Recent example:

month_codes = dict((fn(i+1), code) for i, code in enumerate('FGHJKMNQUVXZ') for fn in (int, str)) 

month_codes result:

{ 1: 'F', 2: 'G', 3: 'H', 4: 'J', ... '1': 'F', '2': 'G', '3': 'H', '4': 'J', ...}

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

EAFP vs. LBYL

It's easier to ask forgiveness than permission

Look before you leap

Generally EAFP is preferred, but not always.

  • Duck typing

If it walks like a duck, and talks like a duck, and looks like a duck: it's a duck. (Goose? Close enough.)

  • Exceptions

Use coercion if an object must be a particular type. If x must be a string for your code to work, why not call

str(x) 

instead of trying something like

isinstance(x, str)

EAFP try/except Example

You can wrap exception-prone code in a try/except block to catch the errors, and you will probably end up with a solution that's much more general than if you had tried to anticipate every possibility.

try: 
    return str(x) 
except TypeError: 
    ... 

Note: Always specify the exceptions to catch. Never use bare except clauses. Bare except clauses will catch unexpected exceptions, making your code exceedingly difficult to debug.

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Moral: don't use wild-card imports!

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Packages

 package/
    __init__.py
    module1.py
    subpackage/
        __init__.py
        module2.py

@xxleyi
Copy link
Author

xxleyi commented Jun 17, 2019

Simple is Better Than Complex

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

—Brian W. Kernighan, co-author of The C Programming Language and the "K" in "AWK"

In other words, keep your programs simple!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment