我正在从David Beazley的视频课程Python Programming Language学习Python。我被困在这个程序中,作者试图通过@typed装饰Holding类。
不幸的是,虽然我认为我逐字复制了代码,但它似乎并没有按计划运行。
我复制了函数类型中的代码,位于底部的main()中。它就像一个魅力。
任何人都可以启发我吗?非常感谢。
from typing import Union, List, Iterator
from pprint import pprint
import csv
# Changes
# make Typed.__init__(self, name=None)
# create def typed(cls)
# decorate class Holding with @typed
# no need for the argument in String(), Integer(), Float()
class Typed:
expected_type = object
def __init__(self, name=None):
self.name = name
def __get__(self, instance, cls):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f'Expected {self.expected_type}')
instance.__dict__[self.name] = value
class Integer(Typed):
expected_type = int
class Float(Typed):
expected_type = float
class String(Typed):
expected_type = str
def typed(cls):
for key, obj in vars(cls).items():
if isinstance(obj, Typed):
obj.name = key
print('in typed():', obj.name)
return cls
@typed
class Holding:
"""Use proxy __setattr__() to limit attributes to design"""
name = String()
shares = Integer()
price = Float()
def __init__(self, name, date, shares, price):
self.name = name
self.date = date
self.shares = shares
self.price = price
def __setattr__(self, name, value):
if name not in {'name', 'date', 'shares', 'price'}:
raise AttributeError(f'No attribute {name}')
super().__setattr__(name, value)
@property
def cost(self):
return self.shares * self.price
def __str__(self) -> str:
return f'{self.shares} shares of {self.name} at {self.price}'
def __repr__(self) -> str:
return f'Holding({self.name}, {self.date}, {self.shares}, {self.price})'
class Portfolio:
def __init__(self):
self.holdings: List[Holding] = []
def __getattr__(self, name): # provide list like behaviour
return getattr(self.holdings, name)
@classmethod
def from_csv(cls, filename: str) -> 'Portfolio':
self = cls()
with open(filename, 'r') as f:
rows = csv.reader(f)
headers = next(rows)
for row in rows:
h: [Holding] = Holding(row[0], row[1], int(row[2]), float(row[3]))
self.holdings.append(h)
return self
def total_cost(self) -> float:
return sum([h.shares * h.price for h in self.holdings])
def __len__(self) -> int:
return len(self.holdings)
def __getitem__(self, index: Union[int, str]) -> Union[Holding, List[Holding]]:
if isinstance(index, str):
return [h for h in self.holdings if h.name == index]
else:
return self.holdings[index]
def __iter__(self) -> Iterator:
return iter(self.holdings)
def main():
h = Holding('ABC', '2018-01-09', 500, 3.45)
print(h.name, h.date, h.shares, h.price, h.cost)
# print(h.name, h.date, h.shares, h.price, h.cost)
# portfolio = Portfolio.from_csv('portfolio.csv')
# pprint(portfolio.holdings)
# portfolio.append(Holding('MAC', '2011-12-01', 125, 90.0))
# print(f'{len(portfolio)} items in the portfolio')
# pprint(portfolio.holdings)
try:
h.shares = 100
h.time = '10:05AM'
except Exception as e:
print(e)
try:
h.shares = "200"
except Exception as e:
print(e)
print(h.name, h.date, h.shares, h.price, h.cost)
for key, obj in vars(Holding).items():
if isinstance(obj, Typed):
obj.name = key
print('in main(): ', obj.name)
if __name__ == '__main__':
main()
这是输出:
你可以看到h实例不对。
预计:ABC 2018-01-09 500 3.45 1725.0
3.45 2018-01-09 3.45 3.45 11.902500000000002
No attribute time
Expected <class 'int'>
100 2018-01-09 100 100 10000
in main(): name
in main(): shares
in main(): price
我发现了这个问题。
def typed(cls):
for key, obj in cls.__dict__.items():
# for key, obj in vars(cls).items(): # Altrenative
if isinstance(obj, Typed):
obj.attrname = key
return cls
返回cls的错误缩进我也将名称更改为attrname,因为我对某些“名称”感到困惑,但这只是为了便于阅读。