Python Tips, Tricks and Hidden Features

8db101b3a812b0464c53e5409c12ea94?s=47 Dustin Ingram
November 21, 2015

Python Tips, Tricks and Hidden Features

November 19th, 2015
Philly Python User's Group

"Python Tips, Tricks and Hidden Features"
(using type, collections, metaclasses and more)

https://github.com/di
http://www.promptworks.com/
http://www.meetup.com/phillypug/
http://phillydev.org/
https://www.youtube.com/watch?v=uWGPxYDo87Q

8db101b3a812b0464c53e5409c12ea94?s=128

Dustin Ingram

November 21, 2015
Tweet

Transcript

  1. Python Tips, Tricks, and Hidden Features (using type, collections, meta-classes,

    and more)
  2. I'm Dustin http://github.com/di

  3. None
  4. Irked.

  5. Irked. >>> j = object() >>> j.hi = 'there' Traceback

    (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'object' object has no attribute 'hi'
  6. type

  7. type >>> type(['foo', 'bar'])

  8. type >>> type(['foo', 'bar']) <type 'list'>

  9. type >>> type(list)

  10. type >>> type(list) <type 'type'>

  11. type >>> type(type)

  12. type >>> type(type) <type 'type'>

  13. type >>> type(None)

  14. type >>> type(None) <type 'NoneType'>

  15. type >>> def func(): ... pass ... >>> type(func)

  16. type >>> def func(): ... pass ... >>> type(func) <type

    'function'>
  17. type >>> import types >>> dir(types) ['BooleanType', 'BufferType', 'BuiltinFunctionType', 'BuiltinMethodType',

    'ClassType', 'CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType', 'EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType', 'GeneratorType', 'GetSetDescriptorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType', 'LongType', 'MemberDescriptorType', 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType', 'SliceType', 'StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', 'UnicodeType', 'XRangeType', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
  18. type >>> import types >>> type(types)

  19. type >>> import types >>> type(types) <type 'module'> >>> type(types)

    == types.ModuleType True
  20. type >>> class FooClass: ... pass ... >>> type(FooClass)

  21. type >>> class FooClass: # Python 2.7 ... pass ...

    >>> type(FooClass) <type 'classobj'>
  22. type >>> class FooClass: # Python 3.4 ... pass ...

    >>> type(FooClass) <class 'type'>
  23. type >>> class FooClass(object): # Python 2.7 ... pass ...

    >>> type(FooClass) <type 'type'>
  24. type >>> type(42) is int True >>> type(42)() 0 >>>

    int() 0
  25. type >>> j = type()

  26. type >>> j = type() Traceback (most recent call last):

    File "<stdin>", line 1, in <module> TypeError: type() takes 1 or 3 arguments
  27. type >>> j = type('FooClass', (object,), {'hi': 'there'}) >>> type(j)

    <class 'type'>
  28. type >>> j = type('FooClass', (object,), {'hi': 'there'}) >>> j.hi

    'there'
  29. type >>> j = type('', (object,), {'hi': 'there'}) >>> j.hi

    'there'
  30. type >>> j = type('', (), {'hi': 'there'}) >>> j.hi

    'there'
  31. type >>> j = type('', (), {}) >>> j.hi =

    'there' >>> j.hi 'there'
  32. type >>> j = object() >>> j.hi = 'there' Traceback

    (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'object' object has no attribute 'hi'
  33. type >>> class FooClass(): ... pass ... >>> hasattr(FooClass(), '__dict__')

    True >>> hasattr(object(), '__dict__') False
  34. type >>> from stackoverflow import getsize¹ >>> getsize(object()) 16 >>>

    getsize(0) 24 >>> getsize(dict()) 280 >>> getsize(FooClass()) 344 1 http://stackoverflow.com/a/30316760/4842627
  35. Questions?

  36. collections

  37. collections >>> def group(names): ... >>> group(['tom', 'dick', 'harry', 'guido'])

    {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  38. collections >>> def group(names): ... d = {} ... >>>

    group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  39. collections >>> def group(names): ... d = {} ... for

    name in names: ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  40. collections >>> def group(names): ... d = {} ... for

    name in names: ... key = len(name) ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  41. collections >>> def group(names): ... d = {} ... for

    name in names: ... key = len(name) ... if key not in d: ... d[key] = [] ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  42. collections >>> def group(names): ... d = {} ... for

    name in names: ... key = len(name) ... if key not in d: ... d[key] = [] ... d[key].append(name) ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  43. collections >>> def group(names): ... d = {} ... for

    name in names: ... key = len(name) ... if key not in d: ... d[key] = [] ... d[key].append(name) ... return d ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  44. collections >>> def group(names): ... d = {} ... for

    name in names: ... key = len(name) ... d.setdefault(key, []).append(name) ... return d ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  45. collections >>> def group(names): ... return { ... length: [

    ... name for name in names if len(name) == length ... ] ... for length in {len(name) for name in names} ... } ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  46. collections.defaultdict >>> from collections import defaultdict >>> def group(names): ...

    d = defaultdict(list) ... for name in names: ... key = len(name) ... d[key].append(name) ... return dict(d) ... >>> group(['tom', 'dick', 'harry', 'guido']) {3: ['tom'], 4: ['dick'], 5: ['harry', 'guido']}   
  47. collections.defaultdict trie: an ordered tree data structure that is used

    to store a dynamic set or associative array where the keys are usually strings2. e.g.: "peter piper picked a peck of pickled peppers" 2 https://en.wikipedia.org/wiki/Trie
  48. collections.defaultdict >>> trie = ... >>> trie['b']['a']['r'] = True >>>

    trie['b']['a']['r'] == True True >>> trie['f']['o']['o'] == True False >>> trie {'b': {'a': {'r': True}}}
  49. collections.defaultdict >>> trie = {} >>> trie['b']['a']['r'] = True Traceback

    (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'b'
  50. collections.defaultdict >>> from collections import defaultdict >>> trie = defaultdict(lambda:

    defaultdict(dict)) >>> trie['b']['a']['r'] = True >>> trie['b']['a']['r'] == True True
  51. collections.defaultdict >>> from collections import defaultdict >>> trie = defaultdict(lambda:

    defaultdict(dict)) >>> trie['b']['a']['r'] = True >>> trie['b']['a']['r'] == True True >>> trie['f']['o']['o'] == True Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'o'
  52. collections.defaultdict >>> from collections import defaultdict >>> trie = defaultdict(lambda:

    defaultdict(dict)) >>> trie['t']['r']['i']['e'] = True Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'i'
  53. collections.defaultdict >>> from collections import defaultdict >>> trie = defaultdict(lambda:

    defaultdict( ... lambda: defaultdict(lambda: defaultdict( ... lambda: defaultdict(lambda: defaultdict( ... dict))))))
  54. collections.defaultdict >>> from collections import defaultdict >>> infinitedict = lambda:

    defaultdict(infinitedict) >>> trie = infinitedict() >>> trie['b']['a']['r'] = True >>> trie['b']['a']['r'] == True True >>> trie['f']['o']['o'] == True False
  55. collections.defaultdict >>> from collections import defaultdict >>> def infinitedict(): ...

    return defaultdict(infinitedict) ... >>> trie = infinitedict() >>> trie['b']['a']['r'] = True >>> trie['b']['a']['r'] == True True >>> trie['f']['o']['o'] == True False
  56. collections >>> def count(names): ... >>> count(['beetlejuice', 'beetlejuice', 'guido']) {'beetlejuice':

    2, 'guido': 1}
  57. collections >>> from collections import defaultdict >>> def count(names): ...

    d = defaultdict(int) ... >>> count(['beetlejuice', 'beetlejuice', 'guido']) {'beetlejuice': 2, 'guido': 1}
  58. collections >>> from collections import defaultdict >>> def count(names): ...

    d = defaultdict(int) ... for name in names: ... d[name] += 1 ... >>> count(['beetlejuice', 'beetlejuice', 'guido']) {'beetlejuice': 2, 'guido': 1}
  59. collections >>> from collections import defaultdict >>> def count(names): ...

    d = defaultdict(int) ... for name in names: ... d[name] += 1 ... return dict(d) ... >>> count(['beetlejuice', 'beetlejuice', 'guido']) {'beetlejuice': 2, 'guido': 1}
  60. collections.Counter >>> from collections import Counter >>> def count(names): ...

    return dict(Counter(names)) ... >>> count(['beetlejuice', 'beetlejuice', 'guido']) {'beetlejuice': 2, 'guido': 1}
  61. Questions?

  62. Metaclasses

  63. Metaclasses >>> class FooClass(): ... pass ...

  64. Metaclasses >>> class FooClass(): ... pass ... >>> a, b

    = FooClass(), FooClass() >>> a is b False
  65. Metaclasses >>> class Singleton(): ... >>> class FooClass(Singleton): ... pass

    ... >>> a, b = FooClass(), FooClass() >>> a is b True
  66. Metaclasses >>> class Singleton(): ... _instance = None ... >>>

    class FooClass(Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  67. Metaclasses >>> class Singleton(): ... _instance = None ... def

    __new__(cls, *args, **kwargs): ... >>> class FooClass(Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  68. Metaclasses >>> class Singleton(): ... _instance = None ... def

    __new__(cls, *args, **kwargs): ... if not cls._instance: ... >>> class FooClass(Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  69. Metaclasses >>> class Singleton(): ... _instance = None ... def

    __new__(cls, *args, **kwargs): ... if not cls._instance: ... cls._instance = object.__new__(cls, *args, **kwargs) ... >>> class FooClass(Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  70. Metaclasses >>> class Singleton(): ... _instance = None ... def

    __new__(cls, *args, **kwargs): ... if not cls._instance: ... cls._instance = object.__new__(cls, *args, **kwargs) ... return cls._instance ... >>> class FooClass(Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  71. Metaclasses classes : instances : : metaclasses : classes

  72. Metaclasses >>> j = type('FooClass', (object,), {'hi': 'there'}) >>> type(j)

    <class 'type'>
  73. Metaclasses >>> j = type('FooClass', (object,), {'hi': 'there'}) >>> type(j)

    <class 'type'> >>> type(j()) <class '__main__.FooClass'>
  74. Metaclasses >>> class MyMeta(type): ... pass ...

  75. Metaclasses >>> class MyMeta(type): ... pass ... >>> class FooClass(metaclass=MyMeta):

    ... pass ...
  76. Metaclasses >>> class MyMeta(type): ... pass ... >>> class FooClass(object):

    # Python 2.7 ... __metaclass__ = MyMeta ...
  77. Metaclasses >>> class MyMeta(type): ... def __new__(meta, name, bases, attrs):

    ... return super().__new__(meta, name, bases, attrs) ... >>> class FooClass(metaclass=MyMeta): ... pass ...
  78. Metaclasses >>> class MyMeta(type): ... def __new__(meta, name, bases, attrs):

    ... print('New {}'.format(name)) ... return super().__new__(meta, name, bases, attrs) ... >>> class FooClass(metaclass=MyMeta): ... pass ... New FooClass
  79. Metaclasses >>> class MyMeta(type): ... def __call__(cls, *args, **kwargs): ...

    print('Call {}'.format(cls.__name__)) ... return super().__call__(*args, **kwargs) ... >>> class FooClass(metaclass=MyMeta): ... pass ... >>> f = FooClass() Call FooClass   
  80. Metaclasses >>> class Singleton(type): ... >>> class FooClass(metaclass=Singleton): ... pass

    ... >>> a, b = FooClass(), FooClass() >>> a is b True
  81. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  82. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  83. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... return super().__new__(meta, name, bases, attrs) ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  84. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... return super().__new__(meta, name, bases, attrs) ... def __call__(cls, *args, **kwargs): ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  85. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... return super().__new__(meta, name, bases, attrs) ... def __call__(cls, *args, **kwargs): ... if not cls._instance: ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  86. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... return super().__new__(meta, name, bases, attrs) ... def __call__(cls, *args, **kwargs): ... if not cls._instance: ... cls._instance = super().__call__(*args, **kwargs) ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  87. Metaclasses >>> class Singleton(type): ... def __new__(meta, name, bases, attrs):

    ... attrs['_instance'] = None ... return super().__new__(meta, name, bases, attrs) ... def __call__(cls, *args, **kwargs): ... if not cls._instance: ... cls._instance = super().__call__(*args, **kwargs) ... return cls._instance ... >>> class FooClass(metaclass=Singleton): ... pass ... >>> a, b = FooClass(), FooClass() >>> a is b True
  88. Questions?

  89. wat

  90. wat #0 >>> x = ... >>> x == x

    False
  91. wat #0 - Possible! >>> x = float('nan') >>> x

    == x False
  92. wat #0 - Possible! >>> x = 0*1e400 >>> x

    == x False
  93. http://python-wats.herokuapp.com/

  94. wat #1 >>> x = ... >>> a = ...

    >>> b = ... >>> c = ... >>> max(x) < max(x[a:b:c]) True
  95. wat #1 - Not Possible >>> x = ... >>>

    a = ... >>> b = ... >>> c = ... >>> max(x) < max(x[a:b:c]) True
  96. wat #2 >>> x = ... >>> y = ...

    >>> min(x, y) == min(y, x) False
  97. wat #2 - Possible! >>> x = {0} >>> y

    = {1} >>> min(x, y) == min(y, x) False
  98. wat #2 - Possible! >>> min({0}, {1}) set([0]) >>> min({1},

    {0}) set([1])
  99. wat #2 - Possible! >>> min({0}, {1}) set([0]) >>> min({1},

    {0}) set([1]) >>> min({0, 1}, {0}) set([0])
  100. wat #2 - Possible! >>> def min(*args): ...

  101. wat #2 - Possible! >>> def min(*args): ... has_item =

    False ... min_item = None ...
  102. wat #2 - Possible! >>> def min(*args): ... has_item =

    False ... min_item = None ... for x in args: ...
  103. wat #2 - Possible! >>> def min(*args): ... has_item =

    False ... min_item = None ... for x in args: ... if not has_item or x < min_item: ...
  104. wat #2 - Possible! >>> def min(*args): ... has_item =

    False ... min_item = None ... for x in args: ... if not has_item or x < min_item: ... has_item = True ... min_item = x ...
  105. wat #2 - Possible! >>> def min(*args): ... has_item =

    False ... min_item = None ... for x in args: ... if not has_item or x < min_item: ... has_item = True ... min_item = x ... return min_item ...
  106. wat #2 - Possible! >>> {1} < {0} False >>>

    {1} < {0, 1} True
  107. wat #2 - Possible! >>> {1} < {0} False >>>

    {1} < {0, 1} True >>> min({0}, {1}) set([0])
  108. wat #3 >>> x = ... >>> y = ...

    >>> any(x) and not any(x + y) True
  109. wat #3 - Not Possible >>> x = ... >>>

    y = ... >>> any(x) and not any(x + y) True
  110. wat #4 >>> x = ... >>> y = ...

    >>> x.count(y) > len(x) True
  111. wat #4 - Possible! >>> x = 'a' >>> y

    = '' >>> x.count(y) > len(x) True
  112. wat #4 - Possible! >>> x = 'a' >>> y

    = '' >>> x.count(y) > len(x) True >>> len('a') 1
  113. wat #4 - Possible! >>> x = 'a' >>> y

    = '' >>> x.count(y) > len(x) True >>> len('a') 1 >>> 'a'.count('') 2
  114. wat #4 - Possible! >>> def count(s, sub): ...

  115. wat #4 - Possible! >>> def count(s, sub): ... result

    = 0 ...
  116. wat #4 - Possible! >>> def count(s, sub): ... result

    = 0 ... for i in range(len(s) + 1 - len(sub)): ...
  117. wat #4 - Possible! >>> def count(s, sub): ... result

    = 0 ... for i in range(len(s) + 1 - len(sub)): ... possible_match = s[i:i + len(sub)] ...
  118. wat #4 - Possible! >>> def count(s, sub): ... result

    = 0 ... for i in range(len(s) + 1 - len(sub)): ... possible_match = s[i:i + len(sub)] ... if possible_match == sub: ... result += 1 ... return result ...
  119. wat #4 - Possible! >>> def count(s, sub): ... result

    = 0 ... for i in range(len(s) + 1 - len(sub)): ... possible_match = s[i:i + len(sub)] ... if possible_match == sub: ... result += 1 ... return result ... >>> count('a', '') 2
  120. wat #4 - Possible! >>> count('foofoof', 'foof') # my implementation

    2 >>> 'foofoof'.count('foof') 1
  121. wat #5 >>> x = ... >>> y = ...

    >>> z = ... >>> x * (y * z) == (x * y) * z False
  122. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False
  123. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1)
  124. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1) == [0]*1
  125. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1) == [0]*1 == [0] True
  126. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1) == [0]*1 == [0] True >>> (x * y) * z == ([0]*-1)*-1
  127. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1) == [0]*1 == [0] True >>> (x * y) * z == ([0]*-1)*-1 == []*-1
  128. wat #5 - Possible! >>> x = [0] >>> y

    = -1 >>> z = -1 >>> x * (y * z) == (x * y) * z False >>> x * (y * z) == [0]*(-1*-1) == [0]*1 == [0] True >>> (x * y) * z == ([0]*-1)*-1 == []*-1 == [] True
  129. wat #6 >>> x = ... >>> y = ...

    >>> x < y and all(a >= b for a, b in zip(x, y)) True
  130. wat #6 - Possible! >>> x = [] >>> y

    = [0] >>> x < y and all(a >= b for a, b in zip(x, y)) True
  131. wat #6 - Possible! >>> x = [] >>> y

    = [0] >>> x < y and all(a >= b for a, b in zip(x, y)) True >>> [] < [0] True
  132. wat #6 - Possible! >>> x = [] >>> y

    = [0] >>> x < y and all(a >= b for a, b in zip(x, y)) True >>> [] < [0] True >>> zip([], [0]) []
  133. wat #6 - Possible! >>> x = [] >>> y

    = [0] >>> x < y and all(a >= b for a, b in zip(x, y)) True >>> [] < [0] True >>> zip([], [0]) [] >>> all([]) True
  134. wat #7 >>> x = ... >>> len(set(list(x))) == len(list(set(x)))

    False
  135. wat #7 - Not Possible >>> x = ... >>>

    len(set(list(x))) == len(list(set(x))) False
  136. wat #8 >>> x = ... >>> min(x) == min(*x)

    False
  137. wat #8 - Possible! >>> x = [[0]] >>> min(x)

    == min(*x) False
  138. wat #8 - Possible! >>> x = [[0]] >>> min(x)

    == min(*x) False >>> min([1, 2, 3]) == min(*[1, 2, 3]) == min(1, 2, 3) True
  139. wat #8 - Possible! >>> x = [[0]] >>> min(x)

    == min(*x) False >>> min([1, 2, 3]) == min(*[1, 2, 3]) == min(1, 2, 3) True >>> min(x) == [0] True
  140. wat #8 - Possible! >>> x = [[0]] >>> min(x)

    == min(*x) False >>> min([1, 2, 3]) == min(*[1, 2, 3]) == min(1, 2, 3) True >>> min(x) == [0] True >>> min(*x) == min([0]) == 0 True
  141. wat #9 >>> x = ... >>> y = ...

    >>> sum(0 * x, y) == y False
  142. wat #9 - Not Possible >>> x = ... >>>

    y = ... >>> sum(0 * x, y) == y False
  143. wat #9 - Not Possible >>> x = ... >>>

    y = ... >>> sum(0 * x, y) == y False >>> sum([1, 1, 1], 7) 10
  144. wat #9 - Not Possible >>> x = ... >>>

    y = ... >>> sum(0 * x, y) == y False >>> sum([1, 1, 1], 7) 10 >>> sum([], 7) 7
  145. wat #10 >>> x = ... >>> y = ...

    >>> y > max(x) and y in x True
  146. wat #10 - Possible! >>> x = 'aa' >>> y

    = 'aa' >>> y > max(x) and y in x True
  147. wat #10 - Possible! >>> x = 'aa' >>> y

    = 'aa' >>> y > max(x) and y in x True >>> max('aa') 'a'
  148. wat #10 - Possible! >>> x = 'aa' >>> y

    = 'aa' >>> y > max(x) and y in x True >>> max('aa') 'a' >>> 'aa' > 'a' True
  149. wat #10 - Possible! >>> x = 'aa' >>> y

    = 'aa' >>> y > max(x) and y in x True >>> max('aa') 'a' >>> 'aa' > 'a' True >>> 'aa' in 'aa' True
  150. Questions?

  151. Thanks!