Python function to send things between 2 users? - python-3.x

I am trying to learn python ( and programming in general). For now I am trying to make a simple bank where users can send/deposit/withdraw money.
I have already created the deposit and withdraw functions and are working. Now I am totally confused on how to write the send function as the user will be sending money and the other will be receiving the money.
Should I write 2 seperate functions fo send and receive, but then how to trigger both in the same time? ( another function containing both) ?
I hope you can help me with this,
so far this is my code:
Classes:
class Account(object):
def __init__(self, name, account_number, initial_amount):
self.name = name
self.no = account_number
self.balance = initial_amount
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def dump(self):
s = '%s, %s, balance: %s' % \
(self.name, self.no, self.balance)
print s
def get_balance(self):
print(self.balance)
def send(self, sender, receiver, amount):
self.sender = sender
self.receiver = receiver
self.balance -= amount
main.py:
from classes.Account import Account
a1 = Account('John Doe', '19371554951', 20000)
a2 = Account('Jenny Doe', '19371564761', 20000)
a1.deposit(1000)
a1.withdraw(4000)
a2.withdraw(10500)
a2.withdraw(3500)
a1.get_balance()
I know this may be basic, but I hope I can get help here.
Thank you

You already have deposit and withdraw methods so you might as well use them.
Transferring money is essentially withdrawing from one account and depositing it in another.
This can be implemented with a static method that accepts 2 accounts and the amount which will encapsulate the idea of "transfer":
class Account:
.
.
.
#staticmethod
def transfer(from_account, to_account, amount):
from_account.withdraw(amount)
to_account.deposit(amount)
# TODO perhaps you will want to use a try-except block
# to implement a transaction: if either withdrawing or depositing
# fails you will want to rollback the changes.
usage:
from classes.Account import Account
a1 = Account('John Doe', '19371554951', 20000)
a2 = Account('Jenny Doe', '19371564761', 20000)
print(a1.balance)
print(a2.balance)
Account.transfer(a1, a2, 10)
print(a1.balance)
print(a2.balance)
# 20000
# 20000
# 19990
# 20010

Related

Simpy: How to implement a resource that handles multiple events at once

I am simulating people movements and their elevator usage. An elevator can take up multiple persons before moving to another floor. The default process has a capacity parameter, however, these indicate the number of processes and not the number of people using the elevator at the same time.
I have tried to use multiple of the resources available, such as Container, Store, and Base. The elevator should be requested and these objects do not have the functionality to be requested. Hence, the only suitable solution is to inherent from the base.Resource class. I have tried to create a subclass Elevator, implementing from base.Resource and adjusting the function _do_get to take multiple elements from the queue. I am pretty confident that this is not the proper way to implement it and it gives an error as well: RuntimeError: <Request() object at 0x1ffb4474be0> has already been triggered. I have no clue which files to adjust to make Simpy happy. Could someone point me in the right direction?
#dataclass
class Elevator(simpy.Resource):
current_floor: int = 0
available_floors: List[int] = field(default_factory=lambda: [0, 1])
capacity: int = 3
# load_carriers: List[LoadCarrier] = field(default_factory=list)
move_time: int = 5
def __init__(self, env: Environment, capacity: int = 1, elevator_capacity: int = 1):
self.elevator_capacity = elevator_capacity
if capacity <= 0:
raise ValueError('"capacity" must be > 0.')
super().__init__(env, capacity)
self.users: List[Request] = []
"""List of :class:`Request` events for the processes that are currently
using the resource."""
self.queue = self.put_queue
"""Queue of pending :class:`Request` events. Alias of
:attr:`~simpy.resources.base.BaseResource.put_queue`.
"""
#property
def count(self) -> int:
"""Number of users currently using the resource."""
return len(self.users)
if TYPE_CHECKING:
def request(self) -> Request:
"""Request a usage slot."""
return Request(self)
def release(self, request: Request) -> Release:
"""Release a usage slot."""
return Release(self, request)
else:
request = BoundClass(Request)
release = BoundClass(Release)
def _do_put(self, event: Request) -> None:
if len(self.users) < self.capacity:
self.users.append(event)
event.usage_since = self._env.now
event.succeed()
def _do_get(self, event: Release) -> None:
for i in range(min(self.elevator_capacity, len(self.users))):
try:
event = self.users.pop(0)
event.succeed()
# self.users.remove(event.request) # type: ignore
except ValueError:
pass
# event.succeed()
So here is the solution I came up with. The tricky bit is I chained two events together. When you queue up for the elevator you get a event that fires when the elevator arrives. This event also returns a second event that fires when you get to your destination floor. This second event is a common event shared by all the passengers that are on the elevator and going to the same floor. Firing this one event notifies a bunch of passengers. This subscribe broadcast pattern can greatly reduce the number of events the model needs to process which in turn improves performance. I use the chained events because if you are in a queue, and the guy in front of you gets on and you do not, then that guy is also going to get off before you, requiring a different destination arrive event. Put another way, I do not know when you will get off until you get on, so I need to defer that part till you actually get onto the elevator.
"""
Simple elevator demo using events to implements a subscribe, broadcast pattern to let passengers know when
they have reached there floor. All the passengers getting off on the same floor are waiting on the
same one event.
Programmer: Michael R. Gibbs
"""
import simpy
import random
class Passenger():
"""
simple class with unique id per passenger
"""
next_id = 1
#classmethod
def get_next_id(cls):
id = cls.next_id
cls.next_id += 1
return id
def __init__(self):
self.id = self.get_next_id()
class Elevator():
""""
Elevator that move people from floor to floor
Has a max compatity
Uses a event to notifiy passengers when they can get on the elevator
and when they arrive at their destination floor
"""
class Move_Goal():
"""
wrapps passengers so we can track where they are going to
"""
def __init__(self, passenger, start_floor, dest_floor, onboard_event):
self.passenger = passenger
self.start_floor = start_floor
self.dest_floor = dest_floor
self.onboard_event = onboard_event
self.arrive_event = None
def __init__(self,env, passenger_cap, floors):
self.env = env
self.passenger_cap = passenger_cap
self.floors = floors
self.on_floor = 0
self.move_inc = 1
# list of passengers on elevator, one per floor
self.on_board = {f:[] for f in range(1,floors + 1)}
# queue for passengers waitting to get on elevator, one queue per floor
self.boarding_queues = {f:[] for f in range(1,floors + 1)}
# events to notify passengers when they have arrived at their floor, one per floor
self.arrive_events = {f: simpy.Event(env) for f in range(1, floors + 1)}
# start elevator
env.process(self._move_next_floor())
def _move_next_floor(self):
"""
Moves the elevator up and down
Elevator stops at every floor
"""
while True:
# move time to next floor
yield self.env.timeout(5)
# update floor elevator is at
self.on_floor = self.on_floor + self.move_inc
# check if elevator needs to change direction
if self.on_floor == self.floors:
self.move_inc = -1
elif self.on_floor == 1:
self.move_inc = 1
# unload and notify passengers that want to get of at this floor
arrive_event = self.arrive_events[self.on_floor]
self.arrive_events[self.on_floor] = simpy.Event(self.env)
arrive_event.succeed()
self.on_board[self.on_floor] = []
# load new passengers
# get open capacity
used_cap = 0
for p in self.on_board.values():
used_cap += len(p)
open_cap = self.passenger_cap - used_cap
# get boarding passengers
boarding = self.boarding_queues[self.on_floor][:open_cap]
self.boarding_queues[self.on_floor] = self.boarding_queues[self.on_floor][open_cap:]
# sort bording into dest floors
for p in boarding:
# give passenger common event for arriving at destination floor
p.arrive_event = self.arrive_events[p.dest_floor]
# notify passeger that they are onboard the elevator
p.onboard_event.succeed()
self.on_board[p.dest_floor].append(p)
def move_to(self, passenger, from_floor, to_floor):
"""
Return a event that fires when the passenger gets on the elevator
The event returns another event that fires when the passager
arrives at their destination floor
(uses the env.process() to convert a process to a event)
"""
return self.env.process(self._move_to(passenger, from_floor, to_floor))
def _move_to(self, passenger, from_floor, to_floor):
"""
Puts the passenger into a queue for the elevator
"""
# creat event to notify passenger when they can get onto the elemator
onboard_event = simpy.Event(self.env)
# save move data in a wrapper and put passenger into queue
move_goal = self.Move_Goal(passenger, from_floor, to_floor, onboard_event)
self.boarding_queues[from_floor].append(move_goal)
# wait for elevator to arrive, and have space for passenger
yield onboard_event
# get destination arrival event
dest_event = self.arrive_events[to_floor]
move_goal.arrive_event = dest_event
return dest_event
def use_elevator(env, elevator, passenger, start_floor, end_floor):
"""
process for using a elevator to move from one floor to another
"""
print(f'{env.now:.2f} passenger {passenger.id} has queued on floor {start_floor}')
arrive_event = yield elevator.move_to(passenger, start_floor, end_floor)
print(f'{env.now:.2f} passenger {passenger.id} has boarded on floor {start_floor}')
yield arrive_event
print(f'{env.now:.2f} passenger {passenger.id} has arrived on floor {end_floor}')
def gen_passengers(env, elevator):
"""
creates passengers to use a elevatore
"""
floor_set = {f for f in range(1, elevator.floors + 1)}
while True:
# time between arrivals
yield env.timeout(random.uniform(0,5))
# get passenger and where they want to go
passenger = Passenger()
start_floor, end_floor = random.sample(floor_set, 2)
# use the elevator to get there
env.process(use_elevator(env, elevator, passenger, start_floor, end_floor))
# boot up
env = simpy.Environment()
elevator = Elevator(env, 20, 3)
env.process(gen_passengers(env, elevator))
env.run(100)

Bank Account Sub classes OOP

B)The BankAccount class should then have two child classes, named SavingsAccount and NonTaxFilerAccount. The SavingsAccount class should have a ZakatDeduction( )function which deducts an amount of 2.5% of the current account balancewhen called. ο‚·The NonTaxFilerAccount class should have the withdraw function from the parent class overwritten. Where a 2% withholding tax is deducted from the account every timea withdrawal is made.
i did the first part but not getting the second one it keeps giving me attribute error
class BankAccount:
def __init__(self, init_bal):
"""Creates an account with the given balance."""
self.init_bal = init_bal
self.account = init_bal
def deposit(self, amount):
"""Deposits the amount into the account."""
self.amount = amount
self.account += amount
def withdraw(self, amount):
self.account -= amount
def balance(self):
print (self.account)
class SavingsAccount(BankAccount) :
def ZakatDeduction(self,amount):
self.account=amount*0.25
print(self.account)
class NonTaxFilerAccount(BankAccount):
def withdraw(self, amount):
self.account -= amount*(0.2)
print(self.account)
x = BankAccount(700)
x.balance()
y=BankAccount
y.SavingsAccount(700)
z=BankAccount
z.withdraw(70)
I think you have several problems. Basically your implementation of the BankAccount, SavingsAccount, and NonTaxFilerAccount classes are structurally correct. However:
Since the instructions say to reduce the account balance by 2.5% every time the ZakatDeduction is called, you should update the method to remove the amount as follows:
def ZakatDeduction(self):
self.account -= self.account*0.025
print(self.account)
Since the instructions say to reduce the account balance by an additional 2% of the withdrawn amount when a NonTaxFiler makes a withdraw3al you should update the NonTaxFiler withdraw method as follows:
def withdraw(self, amount):
self.account -= amount*(1.02)
print(self.account)
Employing these classes to create separate accounte with 700 balance should be as follows:
BA = BankAccount(700) #Create a base account
SA = SavingAccount(700) #Create a Savings Account
NTF = NonTaxFiler(700) #Create a NonTaxFilerAccount
performing the following then yields:
BA.withdraw(25)
BA.balance()
675
SA = SavingsAccount(700)
SA.ZakatDeduction()
682.5
NTF = NonTaxFilerAccount(700)
NTF.withdraw(25)
674.5
The attribute error is correct, and in fact its message tells you the issue. Your classes are ok. The error is in the usage. You have:
y=BankAccount
y.SavingsAccount(700)
This means that the y variable now refers to the BankAccount class. The next line attempts to call y.SavingsAccount, and the BankAccount class does not have a method called SavingsAccount.
Did you perhaps mean:
y = SavingsAccount(700)
Note that python is whitespace specific. While technically valid, for readability, you should use the same level of indentation everywhere, but some of your methods are indented by 4, while others by 3

Using the native TWS Python APi (Interactive Brokers API), how do I get in a variable the price snapshot of a list of securities?

I am new to Python and I would like to get in a variable the price snapshot of a list of securities using the native TWS Python API (Interactive Brokers API).
For example, for the stocks APPL, AMZN and NFLX, I would like to get something like snaphot = ['APPL', 195.2, 'AMZN', 1771.5, 'NFLX', 306].
Thank you in advance for your help.
I found the guide from Interactive Brokers difficult to understand and with a lack of examples.
The one example they provide is for one stock only and it never stops running.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.ticktype import TickTypeEnum
import time
class TestApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
def error(self, reqId, errorCode, errorString):
print("Error: ", reqId, " ", errorCode, " ", errorString)
def tickPrice(self, reqId, tickType, price, attrib):
print("Tick Price. Ticker Id:", reqId, "tickType:",
TickTypeEnum.to_str(tickType), "Price:", price, end=' ')
def tickSize(self, reqId, tickType, size):
print("Tick Size. Ticker Id:", reqId, "tickType:",
TickTypeEnum.to_str(tickType), "Size:", size)
def main():
app = TestApp()
app.connect("127.0.0.1", 7496, 0)
time.sleep(0.1)
contract = Contract()
contract.secType = "FUT"
contract.exchange = "DTB"
contract.currency = "EUR"
contract.localSymbol = "FDXM SEP 19"
app.reqMarketDataType(4) # 1 for live, 4 for delayed-frozen data if live is not available
app.reqMktData(1, contract, "", True, False, [])
app.run()
if __name__ == "__main__":
main()
You would just need to define Contract objects for the stocks, e.g.
Contract definition examples
appl_contract = Contract()
appl_contract.symbol = "AAPL"
appl_contract.secType = "STK"
appl_contract.exchange = "SMART"
appl_contract.primaryExchange = "ISLAND"
appl_contract.currency = "USD"
Then invoke reqMktData with each Contract object, using a unique tickerId argument for each outstanding request (meaning the request is still active). In the tickPrice callback, you receive the returned price data and use the tickerId to match the data to the original request. If you just want the last traded price, you would filter for tickType == 4.
Tick type definitions
After you have received data for the last instrument in your list you could call disconnect() if you want to disconnect/end the program.
You may also be interested in the Python TWS API Traders Academy Course on the IBKR website:

verbose if condition " if not hasattr(self, '__total'):"

I am following "Fluent Python" to learn Function and Design Pattern:
In chapter 6 example-code/strategy.py
class Order: # the Context
def __init__(self, customer, cart, promotion=None):
self.customer = customer
self.cart = list(cart)
self.promotion = promotion
def total(self):
if not hasattr(self, '__total'):
self.__total = sum(item.total() for item in self.cart)
return self.__total
def due(self):
if self.promotion is None:
discount = 0
else:
discount = self.promotion(self) # <1>
return self.total() - discount
def __repr__(self):
fmt = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
I am very confused about:
def total(self):
if not hasattr(self, '__total'):
self.__total = sum(item.total() for item in self.cart)
return self.__total
What's the purpose of if condition here? I guess it could be more readable if:
def total(self):
return sum(item.total() for item in self.cart)
What's the key point I missed? could you please provide any hints?
What happens if you call total more than once? If self.cart hasn't changed, then you're needlessly recalculating the total, a potentially expensive operation.
You're checking if you've already stored the value. If you haven't you calculate it, but if you have you simply return the stored value without recalculating.
As an aside, I would expect name mangling to make your life difficult here because of the double underscore at the beginning of __total. You may want to consider switching to a single underscore.

Understanding the actor model by modeling a bank

I'm trying to understand how the actor model works by modeling a bank. First, here's some code illustrating why we need models for concurrent systems:
import time
from threading import Thread
bank = {'joe': 100}
class Withdrawal(Thread):
"""
Models a concurrent withdrawal for 'joe'. In this example, 'bank'
is a shared resource not protected and accessible from any thread.
Args:
amount (double) how much to withdraw
sleep (bool) config to sleep the thread during the withdrawal
"""
def __init__(self, amount, sleep = False):
self.amount = amount
self.sleep = sleep
Thread.__init__(self)
def run(self):
"""
Overrides method in Thread.
Returns: void
"""
balance = bank['joe']
if balance >= self.amount:
if self.sleep:
time.sleep(5)
bank['joe'] -= self.amount
t1 = Withdrawal(80, True)
t2 = Withdrawal(80)
t1.start()
t2.start()
After running the code, the balance for 'joe' should be -60 after five seconds. This is because bank is unprotected from concurrent access, and pausing for five seconds during concurrent execution means that we can't guarantee that the data won't be accessed at different states. In this case, the first thread accesses the bank after the second thread has finished withdrawing but doesn't check that a withdrawal is still possible. As a result the account goes negative.
If we model the bank and withdrawals as actors, we can protect access to the account since its state is managed on a different thread that's separate from those trying to withdraw from it.
from queue import Queue
from threading import Thread
import time
import random
class Actor(Thread):
"""
Models an actor in the actor model for concurrent computation
see https://en.wikipedia.org/wiki/Actor_model for theoretical overview
Args:
handles (dict) mapping of public methods that are callable
on message data after message has been read
"""
def __init__(self, handles):
self.handles = handles
self.mailbox = Queue()
Thread.__init__(self, daemon=True)
def run(self):
"""
Overrides method in Thread. Once the thread has started,
we listen for messages and process one by one when they are received
Returns: void
"""
self.read_messages()
def send(self, actor, message):
"""
Puts a Message in the recipient actor's mailbox
Args:
actor (Actor) to receive message
message (Message) object to send actor
Returns: void
"""
actor.mailbox.put(message)
def read_messages(self):
"""
Reads messages one at a time and calls the target class handler
Returns: void
"""
while 1:
message = self.mailbox.get()
action = message.target
if action in self.handles:
self.handles[action](message.data)
class Message:
"""
Models a message in the actor model
Args:
sender (Actor) instance that owns the message
data (dict) message data that can be consumed
target (string) function in the recipient Actor to we'd like run when read
"""
def __init__(self, sender, data, target):
self.sender = sender
self.data = data
self.target = target
class Bank(Actor):
"""
Models a bank. Can be used in concurrent computations.
Args:
bank (dict) name to amount mapping that models state of Bank
"""
def __init__(self, bank):
self.bank = bank
Actor.__init__(self, {'withdraw': lambda data: self.withdraw(data)})
def withdraw(self, data):
"""
Action handler for 'withdraw' messages. Withdraw
if we can cover the requested amount
Args:
data (dict) message data
Returns: void
"""
name, amount = data['name'], data['amount']
if self.bank[name] >= amount:
if data['sleep']:
time.sleep(2)
self.bank[name] -= amount
class Withdrawal(Actor):
"""
Models a withdrawal. Can be used in concurrent computations.
Args:
bank (Bank) shared resource to transact with
sleep (bool) config to request that the bank sleep during a withdrawal
"""
def __init__(self, bank, sleep=False):
self.bank = bank
self.sleep = sleep
Actor.__init__(self, {})
def withdraw(self, name, amount):
"""
Wrapper for sending a withdrawl message
Args:
name (string) owner of the account in our bank
amount (double) amount we'd like to withdraw
Returns: void
"""
data = {'sleep': self.sleep, 'name': name, 'amount': amount}
Actor.send(self, self.bank, Message(self, data, 'withdraw'))
Let's now test:
bank = Bank({'joe': 100})
bank.start()
actors = []
for _ in range(100):
a = Withdrawal(bank, random.randint(0, 1))
a.start()
actors.append(a)
for a in actors:
a.withdraw('joe', 15)
Is this understanding correct? Even though the bank sleeps during withdrawals, no simultaneous withdrawal can corrupt the data because it's managed on a different thread than the withdrawals.
Simultaneous withdrawal can no longer occur, true, but it's because the withdraw messages are handled serially, not concurrently, by the single Bank thread inside the Bank.read_messages loop. This means that the sleep commands are also executed serially; the entire message queue is going to stall and yield control for 2 seconds whenever the bank has to sleep during a withdrawal. (Given the Bank's modeled action, this is essentially unavoidable).
If access to an object is isolated to a single thread it is generally considered thread safe.
The other actors cannot access the bank's storage directly but only send messages requesting a withdrawal, so updates only occur in the bank thread and the check-and-set race condition in the original design is eliminated.

Resources