开发者

Using instance attributes as parameters to a method

开发者 https://www.devze.com 2023-04-13 02:23 出处:网络
I have this code I am trying out and I can\'t figure out how to modify the instance attributes when I use them as parameters when calling a method.

I have this code I am trying out and I can't figure out how to modify the instance attributes when I use them as parameters when calling a method.

class Portfolio(object):
    def __init__(self):
        self.qtyA = 50
        self.qtyB = 0
        self.qtyC = 0
        self.cash = 0  

    def __str__(self):
        return ("%d %d %d %.2f")%(self.qtyA, self.qtyB, self.qtyC, self.cash)

    def buy(self, stockQty, qtyToBuy, price, commission=20):
        stockQty += qtyToBuy
        print stockQty
        buyTransaction = price * qtyToBuy
        self.cash -= buyTransaction + commission

>>> p = Portfolio()
>>> p.buy(p.qtyA,10,25)
60
>>> print p
50 0 0 -270.00

What seems to be happening is that a new variable stockQty is being created when buy is called. I would expect that a reference to the attribute qtyA would be passed instead of the value. This problem might be related to this question: H开发者_如何学Cow do I pass a variable by reference?

How can I work around this issue?


This problem might be related to this question: Python: How do I pass a variable by reference?

It is.

How can I work around this issue?

You need to pass a value that can be modified, and modify it. Numbers cannot be modified: a can be changed from referring to 23 to referring to 42 instead, but you cannot cause 23 to become 42 or vice-versa.

In your case, the natural way to do this is to also notice the other silly thing you're doing - using a bunch of related, similarly-named variables in parallel - and fix that as well, by replacing them with a sequence. The list type is a modifiable sequence. You need to pass the list itself instead of just a numeric quantity, and indicate which element of the list to replace. Except you don't actually need to pass the list, because it's already a part of self.

class Portfolio(object):
    def __init__(self):
        self.quantity = [50, 0, 0]
        self.cash = 0  

    def __str__(self):
        return ("%d %d %d %.2f")%(self.quantity[0], self.quantity[1], self.quantity[2], self.cash)

    def buy(self, stockToBuy, amountToBuy, price, commission=20):
        self.quantity[stockToBuy] += amountToBuy
        cost = price * amountToBuy
        self.cash -= cost + commission

For a more flexible solution, you might consider the idea of having an association between stock names and quantities of stock - after all, who knows what stocks the client might want in the future. We can do this simply by using a dict instead.

(A constant 'commission' cost is also unrealistic; a percentage makes more sense.)


A simple approach would be to pass in strings as stockQty containing the name of the member you want to modify (e.g. "qtyA"), and use getattr(self, stockQty) to read and setattr(self, stockQty, newVal) to change the value of this parameter.

If you are not happy about passing in free form strings, you can define some class variables, e.g. refQtyA = "qtyA", and use them as your parameters when you call your function: buy(p.refQtyA, 10, 25).


As @vhallac mentioned you can use setattr or getattr methods to set and get value of attribute respectively. In fact you do not need to pass the object attribute to the function. you can directly access it in the function and update it.:

def buy(self, qtyToBuy, price, commission=20):
    self.qtyA += qtyToBuy
    print self.qtyA
    buyTransaction = price * qtyToBuy
    self.cash -= buyTransaction + commission
>>> p = Portfolio()
>>> p.buy(10,25)
>>> print p
60 0 0 -270.00


I think you should redesign your class. Either write functions buyA, buyB, buyC and make sure to reuse the common code, or refactor buyA, buyB, buyC to a single dictionary which would be updated using a single function buy indexed by a string.

The first proposal is meaningful only if A,B and C have some special business logic meaning in your class.

0

精彩评论

暂无评论...
验证码 换一张
取 消