what's the meaning of creating new variables at a class instance? - python

I am new to OOP programming in python and I was wondering why python let us create new attributes at an object instance. What is the point of creating a new attribute that doesn't follow the design of the class ?
class Shark:
def __init__(self, name, age):
self.name = name
self.age = age
new_shark = Shark("Sammy", 5)
print(new_shark.age)
new_shark.pi = 3.14
print(new_shark.pi)
I expected that python will produce an error but it prints 3.14
*Each answer covered a different spectrum. Thank you very much

Here is a link to a similar question with lots of helpful answers: Why is adding attributes to an already instantiated object allowed?
Now for my answer. Python is a dynamic language meaning that things can be changed at run time for execution. But what is important to realize is that the answer to your question is more a matter of style and opinion.
Instantiating your class with all the needed variables inside of it gives you the benefit of encapsulation and the safety of knowing that every time the class is instantiated that you will have access to that variable. On the other hand adding a variable after instantiation may give you different benefits in specific use cases.

new_shark.pi = 3.14
means add a new attribute to the class object(if not exists).
after the
new_shark.pi = 3.14
the class object will have:
self.name
self.age
self.pi
three attributes

Python and other OOP languages allow classes to inherit from baseclasses and even overide baseclass methods. Imagine the following! You have a base class for all characters in a game. The base class handles things like position, character name, an inventory, clothing, and is responsible for updating and rendering etc... You have an enemy sub-class that handles movement based on some algorithim, and a player sub-class that handles movement based on user input. Maybe the enemy doesn't need an inventory but the player does. Does that make sense?

Related

Design pattern to allow attaching one class to another

I am designing an RPG and would like to have the ability to attach classes to each other. What I'm looking to do is have say an Item class. The weapon class would inherit from it. A sword would be an instance of the weapon class. I want to then be able to attach properties to the sword. These properties would be other classes. For example I could attach the container class to it and the sword (only that instance of the sword) would become a container. I could also maybe attach something like an enchantment to that sword.
For a bonus it would be nice to be able to combine instances as well. So instead of having to have a fire_enchantment class I could just make it an instance of Enchantment and attach it to the sword instance.
I've googled around and haven't been able to find a design pattern that fits this. I recall studying one but can't remember what it was called (Was a few years ago)
I'm at a loss of of which design pattern allowed this. The combining of multiple classes dynamically.
I think you seem to understand the idea of inheritance in python (e.g. class Subclass(Superclass): ) so I won't cover that here.
The classes you want to 'attach' can be treated as any other variable within the Weapon class.
class Enchantment(object):
def __init__(self, name, type):
self.name = name
self.type = type
# can define more member variables here, and set with setter methods
# more Enchantment methods here...
class Weapon(object):
def __init__(self, name, type)
self.name = name
self.type = type
self.enchantments = []
# more Weapon member variables here
def add_enchantment(self, enchantment):
# any logic you need to check when adding an enchantment
self.enchantments.append(enchantment)
Then in wherever your game code is running you could do
sword = Weapon('My sword', 'sword')
fire_enchantment = Enchantment('Fireball', 'fire')
sword.add_enchantment(fire_enchantment)
You can then add methods on the Weapon class to do things with the enchantments/add certain logic.
The enchantment is still an instance of an object, so if you access it in the list (maybe by identifying it by its name, or looping through the list) all its methods and variables are accessible. You just need to build an interface to it via the Weapon class e.g. get_enchantment(self, name), or have other methods in the Weapon class interact with it (e.g. when you attack you might loop through the enchantments and see if they add any extra damage).
There's obviously design considerations about how you design your classes (the above was thrown together for example and doesn't include inheritance). For example you might only allow one enchantment per weapon, in which case you shouldn't use a list in the weapon object, but could just set self.enchantment = None in the constructor, and set self.enchantment = enchantment in the add_enchantment method.
The point I'm making is you can treat instances of Enchantment or other 'attachable' classes as variables. Just make sure you create an instance of the class e.g. fire_enchantment = Enchantment('Fireball', 'fire').
There's plenty of reading out there in terms of inheritance and OOP in general. Hope this helps!
Additional answer from OP
I think the Mixin pattern is what I was looking for. After digging around more I found this post which has an answer for dynamic mixin's.

Understanding subclasses and __init__ method

I have a question.I'm learning Python and trying to understand superclasses,subclasses and the hierarchy between them.I have one thing that i didn't understand completely.
I'm trying to write a program where there's a "Person" superclass and "Birthday" subclass.I defined init method for both of them.What I want to do is, I want to create an instance of Person.At the same time it should create the same instance for Birthday.Because all people have birthdays :) And i want to use the methods that i defined in "Birthday" class.
The code;
import datetime
class Person(object):
def __init__(self,name):
self.name=name
Birthday.__init__(self,name)
def gender(self,gender):
self.gender=gender
class Birthday(Person):
def __init__(self,name):
self.objectlike=[]
self.birthday=None
self.youget={}
def setbirth(self,year,month,day):
self.birthday=datetime.date(year,month,day)
def getbirth(self):
return self.birthday
def __str__(self):
return self.name
def setyouget(self,year,thing):
self.youget[year]=thing
def setlikeob(self,thing):
self.objectlike.append(thing)
def nextbirth(self):
thisyearbirth=getbirth().year.replace(year=datetime.date.today().year)
return thisyearbirth
def howlong(self):
return self.nextbirth()-datetime.date.today()
def getage(self):
age=datetime.date.today().year-self.birthday.year
return age
The problem is when i create an instance of Person,for example,
joey=Person('Joey Tribiani')
Then i try to set a birthday for joey;
joey.setbirth(1980,5,5)
It says:'Person' object has no attribute 'setbirth'
How can i overcome this problem? I think i should add some code to init methods but i don't know what to add.I added "Birthday.init(self,name)" to Person class but it didn't work.
(By the way this is my first question.I read many topics on this website.I'm amazed by how helpful the people using it.)
There are actually two aspects to inheritance - subtyping (semantical) and implementation inheritance (technical).
Semantically, inheritance describes a "is a" relationship - if B is a subclass of A, then B "is a" A (with some specializations), and you should be able to use instances of A and B just the same way (this is known as the Liskov Substitution Principle).
Technically, inheritance is restricted kind of composition / delegation (which is, semantically, a "has a" relationship) - the subclass has a reference to it's parent class, and methods (and other class attributes) not defined in the subclass are looked up on the parent (and it's parent etc). This means inheritance can also be used for code reuse ("implementation inheritance"), eventually without respect for the liskov substitution principle ("type inheritance")
Note that in dynamically typed languages like Python you don't actually need inheritance for subtyping. You can have a class B that implement the exact same interface as class A - and so is a proper subtype according to Liskov - without inheriting from A at all nor have any common ancestor with A.
Now back to your code... The first obvious error is to make Birthday a subclass of Person, since a birthday is obviously not a person (semantically, the relationship is a composition: a person has a birthday). The second obvious error is a cognitive one: it looks like you get the inheritance relationship the wrong way round. If Birthday inherits from Person then it's the Birthday class that get access to Person methods, not the other way round.
There are other obvious issues, but they are of no real importance ATM. First rethink your code in terms of "has a" (composition / delegation), then it will be time to address those issues.
As per the code pasted above Person is the Superclass and Birthday is the Subclass. So, It's the Subclass which inherits from Superclass and not the other way round.
Also, Inheritance is an is-a relationship. Have/Has-A relationship corresponds to composition. You can read more here.

What is this python concept called? Parent class using child-only attributes.

I am writing some code that is an upside down triangle of inheritance. I have a base Linux class that has a CLIENT attr which holds a connection. I have several APIs that are logically separated (kvm, yum, gdb, dhcp, etc..) that use CLIENT but I only want the user to need to create a single instance of Linux class but be able to call all the methods from the Parent classes. While maintaining the nice logical code separation among the parents:
class Linux(
SSHClient,
yum.Yum,
kvm.Kvm,
ldap.Ldap,
lshw.Lshw,
packet_capture.Tcpdump,
tc.TrafficControl,
networking.Networking,
gdb.Gdb,
dhcp.Dhcp,
httputil.Http,
scp.Scp,
fileutils.FileUtils):
I made a little example:
class Dad(object):
def __init__(self):
raise NotImplementedError("Create Baby instead")
def dadCallBaby(self):
print('sup {}'.format(self.babyName))
class Mom(object):
def __init__(self):
raise NotImplementedError("Create Baby instead")
def momCallBaby(self):
print('goochi goo {}'.format(self.babyName))
class Baby(Mom, Dad):
def __init__(self, name):
self.babyName = name
def greeting(self):
self.momCallBaby()
self.dadCallBaby()
x=Baby('Joe')
x.greeting()
What is doing this called? Is this Duck Typing? And is there a better option?
There's really no such thing as "child-only attributes".
The attribute babyName is just stored in each object's namespace, and looked up there. Python doesn't care that it happened to be stored by Baby.__init__. And in fact, you can write store the same attribute on a Mom that isn't a Baby and it will work the same way:
class NotABaby(Mom):
def __init__(self): pass
mom = NotABaby()
mom.babyName = 'Me?'
mom.momCallBaby()
Also, it's hard to suggest a better way to do what you're doing, because what you're doing is inherently confusing and probably shouldn't be done.
Inheritance normally means subtyping—that is, Baby should only be a subclass of Mom if every Baby instance is usable as a Mom.1
But a baby is not a mom and a dad.2 A baby has a mom and a dad. And the way to represent that is by giving Baby attributes for its mom and dad:
class Baby(object):
def __init__(self, mom, dad, name):
self.mom, self.dad, self.name = mom, dad, name
def greeting(self):
self.mom.momCallBaby(self.name)
self.dad.dadCallBaby(self.name)
Notice that, e.g., this means that the same woman can be the mom of two babies. Since that's also true of the real-life thing you're modeling here, that's a sign that you're modeling things correctly.
Your "real" example is a little less clear, but I suspect the same thing is going on there.
The only reason you want to use inheritance, as far as I can tell, is:
I only want the user to need to create a single instance of Linux class
You don't need, or want, inheritance for that:
class Linux(object):
def __init__(self):
self.ssh_client = SSHClient()
self.yum = yum.Yum()
# etc.
… but be able to call all the methods from the Parent classes
If yum.Yum, ldap.Ldap and dhcp.Dhcp both have methods named lookup, which one would be called by Linux.lookup?
What you probably want is to just leave the attributes as public attributes, and use them explicitly:
system = Linux()
print(system.yum.lookup(package))
print(system.ldap.lookup(name))
print(system.dhcp.lookup(reservation))
Or you'll want to provide a "Linux API" that wraps all the underlying APIs:
def lookup_package(self, package):
return self.yum.lookup(package)
def lookup_ldap_name(self, name):
return self.ldap.lookup(name)
def lookup_reservation(self, reservation):
return self.dhcp.lookup(reservation)
If you really do want to just forward every method of all of your different components, and you're sure that none of them conflict with each other, and there are way too many to write out manually, you can always do it programmatically, by iterating all of the classes, iterating inspect.getmembers of each one, filtering out the ones that start with _ or aren't unbound methods, creating a proxy function, and setattr-ing it onto Linux.
Or, alternatively (probably not as good an idea in this case, but very commonly useful in cases that aren't that different), you can proxy dynamically, at method lookup time, by implementing a __getattr__ method (and, often, a __dir__ method).
I think one of these two kinds of proxying may be what you're really after here.
1. There are some cases where you want to inherit for reasons other than subtyping. For example, you inherit a mixin class to get implementations for a bunch of methods. The question of whether your class is usable wherever that mixin's instances are usable doesn't really make sense, because the mixin isn't usable anywhere (except as a base class). But the subtyping is still the standard that you're bending there.
2. If it is, call Child Protective Services. And also call Professor X, because that shouldn't be physically possible.

Avoid putting "global" in every single function

Python is supposed to be fun, simple and easy to learn.
Instead, it's been a huge pain.
I've discovered that all the errors I'm getting are related to me not declaring each variable global in each function.
So for my toy program of dressUp, I have to write:
hatColor = ""
shirtColor = ""
pantsColor = ""
def pickWardrobe(hat, shirt, pants):
global hatColor
global shirtColor
global pantsColor
...
This gets really annoying when I have 20 functions, and each one needs to have 20 global declarations at the beginning.
Is there any way to avoid this?
Thanks!
ADDED
I am getting tons of `UnboundLocalError - local variable X referenced before assignment.
Why am I doing this? Because I need to write a py file that can do some calculations for me. I don't want it all in the same function, or it gets messy and I can't reuse code. But if I split the work among a few functions, I have to declare these annoying globals over and over.
Classes versus global variables
global is common to all
class is a template for an object, representing something, here it could be person dressed up somehow.
Class might have class properties, these are not so commonly used, as they are shared by all instances (sort of "global for classes).
Classes start living as soon as you instantiate them, it means, the pattern defined by class definition is realized in form of unique object.
Such an object, called instance, might have it's own properties, which are not shared with other instances.
I am sometime thinking about a class as of a can - class definition means "can is something you can put thing into" and instance is real tangible can, which has a name of it and in Python I put property values into it, which are bound to the name of given can holder.
DressUp class with real instance properties
Properties in "holmeswatson" solution are bound to class definition. You would run into problems if you would use multiple instances of DressUp, they would be sharing the properties over class definition.
It is better and safer to use it as instance variables, which are over self bound to instance of the class, not to class definition.
Modified code:
class DressUp:
def __init__(self, name, hatColor="", shirtColor=""):
self.name = name
self.hatColor = hatColor
self.shirtColor = shirtColor
def pickWardrobe(self,hat, shirt):
self.hatColor = hat
self.shirtColor = shirt
def __repr__(self):
name = self.name
hatColor = self.hatColor
shirtColor = self.shirtColor
templ = "<Person:{name}: hat:{hatColor}, shirt:{shirtColor}>"
return templ.format(name=name, hatColor=hatColor, shirtColor=shirtColor)
tom = DressUp("Tom")
tom.pickWardrobe("red","yellow")
print "tom's hat is", tom.hatColor
print "simple print:", tom
print "__repr__ call:", tom.__repr__()
jane = DressUp("Jane")
jane.pickWardrobe("pink","pink")
print "jane's hat is", jane.hatColor
print "simple print:", jane
print "__repr__ call:", jane.__repr__()
The __repr__ method is used at the moment, you call print tom or print jane.
It is used here to show, how to instance method can get access to instance properties.
Is there any way around it? Yes, there are several. If you're using global variables on a regular basis, you're making a mistake in your design.
One common pattern when you have many functions that will operate on the same, related data is to create a class and then declare instances of that class. Each instance has its own set of data and methods, and the methods within that instance can operate on the data within that instance.
This is called object oriented programming, it is a common and basic paradigm in modern programming.
Several respondents have sketched out what a class might look like in your case but I don't think you've given enough information (which would include the method signatures of the other functions) to actually write out what you need. If you post more information you might get some better examples.
If it is appropriate, you could use classes.
class DressUp:
def __init__(self, name):
self.name = name
def pickWardrobe(self,hat, shirt, pants):
self.hatColor = hat
self.shirtColor = shirt
self.pantsColor = pants
obj1 = DressUp("Tom")
obj1.pickWardrobe("red","yellow","blue")
print obj1.hatColor
Have a look:
http://www.tutorialspoint.com/python/python_classes_objects.htm

Placing custom class object in a list

I'm fairly new to object oriented programming so some of the abstraction ideas are a little blurry to me. I'm writing an interpreter for an old game language. Part of this has made me need to implement custom types from said language and place them on a stack to be manipulated as needed.
Now, I can put a string on a list. I can put a number on a list, and I've even found I can put symbols on a list. But I'm a bit fuzzy on how I would put a custom object instance on a list when I can't just drop it into a variable (since, after all, I don't know how many there will be and can't go about defining them by hand while the code is running :)
I've made a class for one of the simplest data types-- a DBREF. The DBREF just contains a Database reference number. I can't just use an integer, string, dictionary, etc, because there are type-checking mechanisms in the language I have to implement and that would confuse matters, since those are already used elsewhere in their closes analogues.
Here is my code and my reasoning behind it:
class dbref:
dbnumber=0
def __init__(self, number):
global number
dbnumber=number
def getdbref:
global number
return number
I create a class named dbref. All it does (for now) is take a number and store it in a variable. My hope is that if I were to do:
examplelist=[ dbref(5) ]
That the dbref object would be on the stack. Is that possible? Further, will I be able to do:
if typeof(examplelist[0]) is dbref:
print "It's a DBREF."
else:
print "Nope."
...or am I misunderstanding how Python classes work? Also, is my class definition wonky in any way?
If you used...
class dbref:
dbnumber=0
that would share the same number among all instances of the class, because dbnumber would be a class attribute, rather than an instance attribute. Try this instead:
class dbref(object):
def __init__(self, number):
self.dbnumber = number
def getdbref(self):
return self.dbnumber
self is a reference to the object instance itself that's automatically passed by Python when you call one of the instance's methods.

Categories

Resources