Pretty new to Python so the code below is pretty crude, mainly just for explaining what I have in mind.
What I am trying to do is create objects dynamically from database query. The query would return the fields needed to create the object. However, due to the use of ADO I need to transform the raw values before initialising the class.
Possible improvements to the pseudo code below would be to return the class name in the query and/or to use kwargs with the db column name as the key.
Using Python 3.6.
def main():
dbRow = GetAPersonRowFromDB()
personFromRow = CreateObjectFromDatabase(Person, dbRow, "name", "gender")
def transform(value):
transformedValue = #do something to the value
return transformedValue
def CreateObjectFromDatabase(className, *args):
transformedArgs = []
# apply transform() to each *args item
for arg in args:
transformedArgs.append(transform(dbRow[arg]))
obj = className(transformedArgs)
return obj
class Person:
def __init__(self, name, gender):
self.Name = name
self.Gender = gender
def __init__(self, *args):
self.Name = args[0]
self.Gender = args[1]
I ended up using derived classes from a base class. I'm sure it can be done in a more elegant way but this works with minimal boiler plate code.
# a dynamic object that gets constructed from kwargs
class DataObject(object):
#classmethod
def fromDictionary(cls, **kwargs):
return cls(**kwargs)
#classmethod
def type(cls):
return cls.__module__ # will only work if each class is in its own module
class Person(DataObject):
# DB column names must match parameter names
def __init__(self, name, gender):
self.Name = name
self.Gender = gender
def CreateObjectFromDatabase(className, recRow):
transformedArgs = {}
for i in range(recRow.Fields.Count):
item = recRow.Fields.Item[i]
transformedArgs[str.lower(item.Name)] = TransformSomehow(item.Value)
obj = className.fromDictionary(**transformedArgs)
return obj
def main():
dbRow = GetAPersonRowFromDB()
personFromRow = CreateObjectFromDatabase(Person, dbRow)
Was playing around with using type() method to create the object e.g.
type('Person', (DataObject, ), transformedArgs)
But this creates objects of Type 'type' which didn't work for my purpose.
Related
I want to make a method whose arguments are an arbitrary class and a list of instances.
let's say the name of the class is 'Price' and the name of the list is 'price_list'
def CreateHTML(_class, _list):
one_instance = _class
list_members = list(one_instance.__dict__) ##to get the list of member variables' names
n= len(list_members)
CreateHTML(Price(), price_list)
but the problem is that it works well only if I initially set 'None' values to all arguments of 'Price' class.
class Price:
def __init__(self, name= None, data = None):
self.name = name
self.data = data
is there any ways that the assignment of 'None' values can be automatically handled inside the CreateHTML method??? so that i don't need to initially set Nones to the class. (like below)
class Price:
def __init__(self, name, data):
self.name = name
self.data = data
Thanks!!!
CreateHTML(Price(), price_list) : here Price is expecting 2 items 'name' and 'data'. You have to either pass it while calling the Price('name', 'data') or you have to pass None in your init
As also noted in my comment above, Price() isn't a class, it is an instance of the class Price. By calling Price() you are essentially instantiating Price with all variables as None. This will only work if Price has default argments such as is set with def __init__(self, name= None, data = None).
If you want a general method with which to instantiate arbitrary classes, you can create something like the following, which takes an arbitrary class and instantiates it will arbitrary arguments (*args) and keyword arguments (**kwargs):
class Price:
def __init__(self, name, data):
self.name = name
self.data = data
def create_instance(my_class, *args, **kwargs):
return my_class(*args, **kwargs)
def CreateHTML(one_instance):
list_members = list(one_instance.__dict__) ##to get the list of member variables' names
n= len(list_members)
print(f"This instance has {n} members")
one_instance1 = create_instance(Price, name="Hello", data="World")
one_instance2 = create_instance(Price, name=None, data=None)
CreateHTML(one_instance1)
CreateHTML(one_instance2)
You can use create_instance for any class and any arguments, e.g.:
class SomeClass:
def __init__(self, foo, bar):
self.foo = foo
self.bar= bar
one_instance3 = create_instance(SomeClass, "hello", bar="World")
Although to be honest, you don't really gain some much from this. Might as well just use:
one_instance1 = Price(name="Hello", data="World")
one_instance2 = Price(name=None, data=None)
one_instance3 = SomeClass("hello", bar="World")
I have a class Team, I want to write a Unit test for it,
class name team.py
class Team()
def __init__(self, args):
if args.player:
self.player_name = args.player
self.sports = ''
def test__init__(self):
test1 = team.Team(player="deepak")
While executing this, I am getting error like:
AttributeError: "'str' object has no attribute 'player'"
I know it is very basic but right not I need some quick help to use this. I am not aware how to access this while creating object in test file.
Arguments and keyword arguments don't work like that in python. The closest to what you want would be to use kwargs to get a dict of params.
class Team():
def __init__(self, **kwargs):
if kwargs["player"]:
self.player_name = kwargs["player"]
self.sports = ""
test1 = Team(player="deepak")
See https://docs.python.org/3/tutorial/classes.html for some good docs on how python classes work.
EDIT
Since you can't edit the code, you need to have args be an object with the member player.
from collections import namedtuple
class Team():
def __init__(self, args):
if args.player:
self.player_name = args.player
self.sports = ""
TeamArguments = namedtuple("TeamArguments", ["player"])
test1 = Team(TeamArguments(player="deepak"))
Suppose I have a data structure composed of objects in Python like this:
class Planet:
def __init__(self, name):
self.name = name
self.continents = []
class Continent:
def __init__(self, name):
self.name = name
self.countries = []
class Country:
def __init__(self, name):
self.name = name
self.states = []
class State:
def __init__(self, name):
self.name = name
self.cities = []
class City:
def __init__(self, name):
self.name = name
Now suppose I was to create a function that would be able to take an object and an attribute "path" as parameters and output a list of all the objects that "match" that path. Since I don't really know how to describe very well what I'm thinking of and most likely I'm using the wrong terminology, here is an idea of what it might look like in practice (let's call the function collect, and assume that the data structure is populated with data, with planet being the "root" object of the data structure):
planet = Planet("Earth")
... Code for populating data structure ...
collect(planet, "continents.countries.states.cities")
This function call would return a list of every cities in every state in every country in every continent on the planet. Or if I wanted all the states in the data model I would do:
collect(planet, "continents.countries.states")
Hopefully you get the idea. The problem is that I just have no clue how I would accomplish this. Here's what I've come up with so far:
def collect(obj, attr_path):
attrs = attr_path.split(".")
current_attr = obj
items = []
for attr in attrs:
current_attr = getitem(current_attr, attr)
# Not sure what to do here...
return items
Does anyone know how I can make this work?
If you would like to do a breadth first search:
def bfs(queue, results):
try:
obj, attr_path = queue.pop(0)
except IndexError:
return
if attr_path is None:
results.append(obj)
else:
if '.' in attr_path:
first, rest = attr_path.split('.', maxsplit=1)
else:
first, rest = attr_path, None
children = getattr(obj, first)
for child in children:
queue.append((child, rest))
bfs(queue, results)
def collect(obj, attr_path):
queue = [(obj, attr_path)]
results = []
bfs(queue, results)
return results
Disclaimer: untested
I have 3 files. The first is a Runners file which is abstract. The other two are CharityRunner and ProfessionalRunners. In these I can create runners.
Runners:
class Runner(object):
def __init__ (self, runnerid, name):
self._runnerid = runnerid
self._name = name
#property
def runnerid(self):
return self._runnerid
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
def get_fee(self, basicfee, moneyraised):
raise NotImplementedError("AbstractMethod")
CharityRunners:
from Runner import *
class CharityRunner(Runner):
def __init__ (self, runnerid, name, charityname):
super().__init__(runnerid, name)
self._charityname = charityname
#property
def charityname(self):
return self._charityname
#charityname.setter
def charityname(self, charityname):
self._charityname = charityname
def get_fee(self, basicfee, moneyraised):
if moneyraised >= 100:
basicfee = basicfee * 0.25
elif moneyraised >= 50 and moneyraised < 100:
basicfee = basicfee * 0.5
else:
basicfee = basicfee
return basicfee
ProfessionalRunners:
from Runner import *
class ProfessionalRunner(Runner):
def __init__ (self, runnerid, name, sponsor):
super().__init__(runnerid, name)
self._sponsor = sponsor
#property
def sponsor(self):
return self._sponsor
#sponsor.setter
def sponsor(self, sponsor):
self._sponsor = sponsor
def get_fee(self, basicfee):
basicfee = basicfee * 2
return basicfee
Now I have also created a club object that has a club id and club name. There is also a list called self._runners = []. I'm trying to get a add function that will add the runners created in the list. But it must make sure that the runner is not already in the list.
The object printing method should be in the format of:
Club: <club id> <club name>
Runner: <runner id 1> <runner name 1>
Runner: <runner id 2> <runner name 2>
At the moment I only have this for the club object:
from Runner import *
class Club (object):
def __init__(self, clubid, name):
self._clubid = clubid
self._name = name
self._runners = []
#property
def clubid(self):
return self._clubid
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
def add_runner(self):
self._runner.append(Runner)
I'm guessing the part you're missing is:
im trying to get a add function that will add the runners created in the list.
Your existing code does this:
def add_runner(self):
self._runner.append(Runner)
This has multiple problems.
First, you're trying to modify self._runner, which doesn't exist, instead of self._runners.
Next, you're appending the Runner class, when you almost certainly want an instance of it, not the class itself.
In fact, you almost certainly want an instance of one of its subclasses.
And I'm willing to bet you want a specific instance, that someone will pass to the add_runner function, not just some random instance.
So, what you want is probably:
def add_runner(self, runner):
self._runners.append(runner)
And now that you posted the UML diagram, it says that explicitly: add_runner(Runner: runner). In Python, you write that as:
def add_runner(self, runner):
Or, if you really want:
def add_runner(self, runner: Runner):
… but that will probably mislead you into thinking that this is a Java-style definition that requires an instance of Runner or some subclass thereof and checks it statically, and that it can be overloaded with different parameter types, etc., none of which is true.
To use it, just do this:
doe_club = Club(42, "Doe Family Club")
john_doe = CharityRunner(23, "John Doe", "Toys for John Doe")
doe_club.add_runner(john_doe)
Next:
But it must make sure that the runner is not already in the list.
You can translate that almost directly from English to Python:
def add_runner(self, runner):
if runner not in self._runners:
self._runners.append(runner)
However, this does a linear search through the list for each new runner. If you used an appropriate data structure, like a set, this wouldn't be a problem. You could use the same code (but with add instead of append)… but you don't even need to do the checking with a set, because it already takes care of duplicates for you. So, if you set self._runners = {}, you just need:
def add_runner(self, runner):
self._runners.add(runner)
I have no idea what is wrong! This is a very simple program and I have done a lot head banging! Please someone enlighten me!
This a lab problem from the CSE 111 - Programming Language II course. They teach Java at the university and the code I wrote in Java works fine.
I just have to create a Student class with some fields to hold the basic information about a student with methods to get and set the attributes. Then create an instance of that class and tryout the methods.
But every time I run this program the following error occurs:
TypeError: set_name() takes exactly 1 positional argument (2 given)
Here is the code I wrote.
class Student:
'''Student class'''
name = None
id = 0
address = None
cgpa = None
def get_name():
return name
def set_name(n):
name = n
def get_id():
return id
def set_id(i):
id = i
def get_address():
return address
def set_address(a):
address = a
def get_cgpa():
return cgpa
def set_cgpa(c):
cgpa = c
#An object of Student class
jack = Student()
jack.set_name('jacky')
print(jack.get_name())
You're not accepting a reference to your instance as the first argument to that method, i.e. your set_name() should be written:
def set_name(self, n):
self.name = n
This is somewhat different from other languages where there is a built-in keyword (such as this) that refers to the current object. Python passes that reference explicitly, as an argument to the method.
All your other methods must be modified similarly.
Note that just setting name = n sets a local variable name which goes away when the method ends; it does not set anything on the instance. You have to explicitly set self.name if you want an instance attribute.
Also, and this is a matter of style, but you do not usually write set and get methods in Python. It is normal practice to set and get attributes directly. If you want to do validation of values, use a property instead. So basically, none of your methods are actually necessary in good style.
However, you don't have an __init__() method. Usually you would pass the desired attributes of the instance when instantiating the class and save these on the instance.
class Student:
def __init__(self, name, id, address, cgpa):
self.name = name
self.id = id
self.address = address
self.cgpa = cgpa
herman = Student("Herman Munster", 12345, "1313 Mockingbird Lane", 4.0)
Try this:
import sys
class Student:
'''Student class'''
self.name = None
self.id = 0
self.address = None
self.cgpa = None
def get_name(self):
return self.name
def set_name(self, n):
self.name = n
def get_id(self):
return self.id
def set_id(self, i):
self.id = i
def get_address(self):
return self.address
def set_address(self, a):
self.address = a
def get_cgpa(self):
return self.cgpa
def set_cgpa(self, c):
self.cgpa = c
You need to pass self as the first argument to each member function of the class. Member variables must then be referred to with self, i.e. self.name. Furthermore, you may wish to include an __init__() function; this serves usually to initialize any member variables, and is called at the instantiation of the class.
Take a look at the Python documentation here for some examples on well-formed classes: http://docs.python.org/tutorial/classes.html#random-remarks
In Python, you need to pass in self for each of your member functions. You also need to reference class variables as self.x, if you want them to take an effect.
Here are a couple examples that you need to apply to the rest of your code.
def set_name(self, n):
self.name = n
def get_cgpa(self):
return self.cgpa
There is some explanation for why this is the case in the documentation.
This is because first argument of methods is self - the class instance.
See What is the purpose of self?
and http://docs.python.org/tutorial/classes.html#class-objects