Lecture 18 --- HW 04 
Lecture 18 Objects 
1 

关于 class 和 object 之间的关系的形容
引述
关于 class 和 object 的解释:
- class: A class combines (and abstracts) data and functions
- object: An object is an instantiation of a class
2 

类内的方法在编写是,第一个参数须是 self ,
但类内方法在被调用的时候,不需要传入 self 的值,或者说 self 就是调用方法的实例,所以只需要传入之后的参数
3 

python有内置函数可以查询/访问类的实例的属性(attribute),或者是类的属性 (类内的方法算作是类本身的属性,而不是具体实例的属性)
getattr() 可以访问属性,获取对应的值
hasatrr() 可以看是否有某个属性
函数的第一个参数需要传入实例,第二个参数需要传入要查询的属性的属性名(以字符串传入)
4 

如上图,类名.方法名 是一个函数,并且 self 参数需要传入东西,而 对象.方法名 是一个方法,self 不用传
5 

类属性
如上图,在类中赋值的变量,(应该)就是类的属性(类内的方法也算是类的属性,第3点有提到过),
类属性不是对象/实例的一部分,而是类的一部分。每次通过对象来访问类属性,访问的是类中的属性,而通过 对象.属性名 赋值/更改属性,其实是在对象中创建/更改对应的属性(所以通过对象修改“类属性”不会更改实际的类属性)
Lecture 18 Q&A 
1 
类属性除了可以在类内定义,也可以在类以外,通过 类名.属性名 的形式赋值去定义,如
class Account:
    ...
    
Account.interest = 0.03python>>> Account.interest 0.03 >>> a = Account('John') >>> a.interest 0.03 >>> a.interest = 0.05 >>> a.interest 0.05 >>> b = Account('Hany') >>> b.interest 0.03 >>> a.interest 0.05 >>> a.interest = Account.interest >>> a.interest 0.03 >>> Account.interest = 0.04 >>> a.interest 0.03 >>>
John的这段代码演示,显示了通过对象来修改“类属性”(指相同的名字)时,其实是修改的是具体对象中的属性
类和对象两者各自的修改都不会影响到对方的属性
del 语句,经过测试,是可以将对象中已有的属性清除掉,从而再次访问相同的属性名时,获取到的是类属性的值
>>> class Account:
...     def __init__(self):
...         return
...
>>> Account.interest = 5
>>> p1 = Account()
>>> p1.interest
5
>>> del p1.interest
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: interest
>>> p1.interest += 2
>>> p1.interest
7
>>> Account.interest
5
>>> del p1.interest
>>> p1.interest
5
>>> del p1.interest
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: interest
>>>2 

del 也可以删除列表中的元素,
但是John说 del 不常用
HW 04 
1 
Q4
TIP
Hint: If you had the permutations of all the elements in seq not including the first element, how could you use that to generate the permutations of the full seq?
这个提示很有用:考虑每次抽去其中一个元素的情况,然后依次递归...
一开始感觉能用推导式写成一行
def permutations(seq):
    yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:]) for i in range(len(seq))]然后发现,i 只对 permutations(seq[:i] + seq[i + 1:]) 生效,[seq[i]] 中 i 显示未定义
然后改成
def permutations(seq):
    for i in range(len(seq))
        yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])]然后在测试文档的一个测试用例中,用 next() 使用函数返回的生成器,显示 StopIteration ,
思考了很久,发现是因为,递归到了最后, permutations(seq[:i] + seq[i + 1:]) 传入的是空列表,那么就不能解压出 p ,那么推导式的结果就会是空的列表,再一层层返回,所以最后整体的函数返回的生成器中没有可以迭代的元素
所以需要设置 base case ,(一开始以为不需要设置,或者说以为空列表就可以作为 base case)
def permutations(seq):
    if len(seq) == 1:
        yield seq
    else:
        yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])]然后发现,测试文档中,有一个传入了元组,所以我稍加了修改
def permutations(seq):
    seq = list(seq)
    if len(seq) == 1:
        yield seq
    else:
        yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])]后面发现,其实这样改也可以:
pythondef permutations(seq): if len(seq) == 1: yield [seq[0]] else: yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])]
在思索到底一行语句实现功能是否可行时,想到了 sum() 函数,想到可以用它来把结果合并在一个列表中
def permutations(seq):
    yield from sum([[... for p in permutations(seq[:i] + seq[i + 1:])] for i in range(len(seq))], start=[])然后想到可以把 base case 放在 sum 函数外面
def permutations(seq):
    yield from [[seq[0]]] if len(seq) == 1 else sum([[[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])] for i in range(len(seq))], start=[])代码
def permutations(seq):
    """Generates all permutations of the given sequence. Each permutation is a
    list of the elements in SEQ in a different order. The permutations may be
    yielded in any order.
    >>> perms = permutations([100])
    >>> type(perms)
    <class 'generator'>
    >>> next(perms)
    [100]
    >>> try: #this piece of code prints "No more permutations!" if calling next would cause an error
    ...     next(perms)
    ... except StopIteration:
    ...     print('No more permutations!')
    No more permutations!
    >>> sorted(permutations([1, 2, 3])) # Returns a sorted list containing elements of the generator
    [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
    >>> sorted(permutations((10, 20, 30)))
    [[10, 20, 30], [10, 30, 20], [20, 10, 30], [20, 30, 10], [30, 10, 20], [30, 20, 10]]
    >>> sorted(permutations("ab"))
    [['a', 'b'], ['b', 'a']]
    """
    "*** YOUR CODE HERE ***"
    # seq = list(seq)
    # if len(seq) == 1:
    #     yield seq
    # else:
    #     for i in range(len(seq)):
    #         yield from [[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])]
    yield from [[seq[0]]] if len(seq) == 1 else sum([[[seq[i]] + p for p in permutations(seq[:i] + seq[i + 1:])] for i in range(len(seq))], start=[])2 
Q5
Use
type(value) == strto test if somevalueis a string
可以使用 type(value) == str 来判断一个东西是否是字符串
感觉我最后答案中的这一行是关键的地方:
def make_joint(with_draw, old_pass, new_pass):
    def joint(amount, pw_input):
        ...
        return withdraw(amount, pw_input)  # key point
    ...
    return joint代码
def make_joint(withdraw, old_pass, new_pass):
    """Return a password-protected withdraw function that has joint access to
    the balance of withdraw.
    >>> w = make_withdraw(100, 'hax0r')
    >>> w(25, 'hax0r')
    75
    >>> make_joint(w, 'my', 'secret')
    'Incorrect password'
    >>> j = make_joint(w, 'hax0r', 'secret')
    >>> w(25, 'secret')
    'Incorrect password'
    >>> j(25, 'secret')
    50
    >>> j(25, 'hax0r')
    25
    >>> j(100, 'secret')
    'Insufficient funds'
    >>> j2 = make_joint(j, 'secret', 'code')
    >>> j2(5, 'code')
    20
    >>> j2(5, 'secret')
    15
    >>> j2(5, 'hax0r')
    10
    >>> j2(25, 'password')
    'Incorrect password'
    >>> j2(5, 'secret')
    "Frozen account. Attempts: ['my', 'secret', 'password']"
    >>> j(5, 'secret')
    "Frozen account. Attempts: ['my', 'secret', 'password']"
    >>> w(5, 'hax0r')
    "Frozen account. Attempts: ['my', 'secret', 'password']"
    >>> make_joint(w, 'hax0r', 'hello')
    "Frozen account. Attempts: ['my', 'secret', 'password']"
    """
    "*** YOUR CODE HERE ***"
    def joint(amount, pw_input):
        if pw_input == new_pass:
            return withdraw(amount, old_pass)
        else:
            return withdraw(amount, pw_input)
    old_result = withdraw(0, old_pass)
    if type(old_result) == str:
        return old_result
    return joint3 
Q6
代码
def remainders_generator(m):
    """
    Yields m generators. The ith yielded generator yields natural numbers whose
    remainder is i when divided by m.
    >>> import types
    >>> [isinstance(gen, types.GeneratorType) for gen in remainders_generator(5)]
    [True, True, True, True, True]
    >>> remainders_four = remainders_generator(4)
    >>> for i in range(4):
    ...     print("First 3 natural numbers with remainder {0} when divided by 4:".format(i))
    ...     gen = next(remainders_four)
    ...     for _ in range(3):
    ...         print(next(gen))
    First 3 natural numbers with remainder 0 when divided by 4:
    4
    8
    12
    First 3 natural numbers with remainder 1 when divided by 4:
    1
    5
    9
    First 3 natural numbers with remainder 2 when divided by 4:
    2
    6
    10
    First 3 natural numbers with remainder 3 when divided by 4:
    3
    7
    11
    """
    "*** YOUR CODE HERE ***"
    def helper(i):
        # yield from [n * m + i for n in naturals()]
        if i != 0:
            yield i
        for n in naturals():
            yield n * m + i
    yield from [helper(i) for i in range(m)]