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.03
python>>> 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) == str
to test if somevalue
is 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 joint
3
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)]