Why Assign Class Fields Outside Constructor - python

I recently saw code that assigns a list to an object's field after the constructor is invoked.
# Inside the "Block" class definition
def __init__(self, name, access, address=None):
ModuleBS.__init__(self, name, address)
self.access = access
self.mem_list = []
# Calling the constructor
tmp_blk = Block(block_name, name, access, sys_addr)
tmp_blk.mem_list = memory_list ## assignment occurs after constructor invoked
Is there a reason for this? Why would this be preferred over initializing mem_list inside the constructor instead, passing memory_list as a constructor argument?
Thanks

First things first, mem_list IS being initialised in class' __init__:
# Inside the "Block" class definition
def __init__(self, name, access, address=None):
...
self.mem_list = []
Later call was just an value change - some would just use append() or insert(), some would just pass existing list.
As for your second question, it's perfectly okay to do it both way - I'm mostly writing my classes that way I can initialise some variable with class call, with a simple check to see if data passed is valid, and later change that variable on demand - as long as I my init method's doesn't have a bunch of parameters.
In that case it may be just simpler to initialise a class with only necessary fields (with some 'default' values for other) and later just change those values directly.

Related

How would I pythonically declare objects with method arguments as a class's instance attributes?

I have a class that, among other things, contains a function object which used to compute some data.
class Container:
def __init__(self, function):
self.function = function
# Example attribute.
self.x = 10
I also have a class that has multiple Containers and their respective functions.
class Entity:
def __init__(self):
# Other things.
self.container_1 = Container(self.container_function_1)
self.container_2 = Container(self.container_function_2)
def container_function_1(self):
# Generate data.
return data
def container_function_2(self):
# Generate data.
return data
This is so that I can get the relevant data by calling the Container's function through an instance of Entity, like this:
entity_instance = Entity()
data = entity_instance.container_1.function()
Is there any way that I can more pythonically declare Containers inside Entity?
In other words, is there any functionality I could add to Container or Entity that lets me declare a Container inside an Entity without having to write it out in two different places?
My first thought was that I could use a class decorator, like this:
class Entity:
def __init__(self):
# Other things.
#Container
def container_1(self):
# Generate data.
return data
#Container
def container_2(self):
# Generate data.
return data
But, since the methods are decorated before the Entity instance is initialized, the Container instances are declared as class attributes, not instance attributes, and so they have no access to self.
You can fix this by making Container a descriptor, like this:
class Container:
def __init__(self, function):
self.function = function
# Example attribute.
self.x = 10
def __get__(self, instance, owner):
from functools import partial
return Container(partial(self.function, instance))
The __get__ dunder just returns a new Container who's function has access to the object it was accessed from, much like python does with methods already.
The issue is that it's generating a whole new Container instance every time you access the attribute. This means that when you access the Container from the Entity instance in order to modify any of it's attributes, like this:
entity_instance = Entity()
entity_instance.container_1.x = 20
Accessing entity_instance.container_1.x gives you 10, not 20, since the Container.__get__ produces a new, unmodified Container instance, and the modified instance is lost.
The way I can think of to side step this issue would have to involve the Entity constructor deliberately going through its own directory, finding any class attributes of type Container, and overwriting them with instance attributes.
Is there any way to work around this? And if not, is there any other piece of python functionality, aside from class decorators, that would let me pythonically declare new Containers in Entity?

Calling type(dict) functions within classes on class variables (Python 3.4)

I am creating a class and trying to define class variables that correspond to a function like .keys() or .values() that are called on another class variable.
For example:
class DATA(object):
def __init__(self, id, database = {}):
self.id = id
self.database = database
self.addresses = database.keys()
self.data = database.values()
This does not seem to work, as when I create an instance of the class
foo = DATA(0,{"a":1,"b":2})
and then ask for:
print(foo.addresses)
>>> []
and it gives back an empty list.
Note:
On my actual program I start out with an empty dictionary for any class instance, then later on I use a function to add to the dictionary. In this case calling the ".database" still works but ".addresses" does not.
Can anyone help me with this problem?
I'm not sure that this is the problem, but using a mutable such as {} as a default argument often leads to bugs. See: "Least Astonishment" and the Mutable Default Argument
This is safer:
def __init__(self, id, database=None):
if database is None:
self.database = {}
else:
self.database = database
I don't understand the purpose of DATA.addresses and DATA.data. Could you use functions with the property decorator instead, to avoid redundancy?
#property:
def addresses(self):
return self.database.keys()
#property:
def data(self):
return self.database.values()
The issue is that you're calling keys right in your __init__ method, and saving the result. What you want to do instead is to call keys only when you want to access it.
Now, depending on the requirements of your class, you may be able to do this in a few different ways.
If you don't mind exposing changing the calling code quite a bit, you could make it very simple, just use foo.database.keys() rather than foo.addresses. The latter doesn't need to exist, since all the information it contains is already available via the methods of the databases attribute.
Another approach is to save the bound instance method database.keys to an instance variable of your DATA object (without calling it):
class DATA(object)
def __init__(self, database=None):
if database is None:
database = {}
self.database = database
self.addresses = database.keys # don't call keys here!
In the calling code, instead of foo.addresses you'd use foo.addresses() (a function call, rather than just an attribute lookup). This looks like a method call on the DATA instance, though it isn't really. It's calling the already bound method on the database dictionary. This might break if other code might replace the database dictionary completely (rather than just mutating it in place).
A final approach is to use a property to request the keys from the database dict when a user tries to access the addresses attribute of a DATA instance:
class DATA(object)
def __init__(self, database=None):
if database is None:
database = {}
self.database = database
# don't save anything as "addresses" here
#property
def addresses(self):
return self.database.keys()
This may be best, since it lets the calling code treat addresses just like an attribute. It will also work properly if you completely replace the database object in some other code (e.g. foo.database = {"foo":"bar"}). It may be a bit slower though, since there'll be an extra function call that the other approaches don't need.

Is it possible in Python to make a set of methods of a class dependent on input of constructor?

I am reading this Genshi Tutorial and see there the following example:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
As far as I understand this example, we create a new class that inherits Schema class and this class contain three methods: username, url, title. However, I am not sure about the last because before I only saw methods created with def.
Anyway, my question is not about that. I would like to know if it is possible to make the definition of the class dynamic. For example, sometimes I do not want url or title to be in the class. It seems to be doable (I just use if and assign a value to url only if-statement is satisfied.
But what if I do not know in advance what fields I would like to have in the form? For example, now I have username, url and title. But what if later I would like to have city or age. Can I do something like that:
from formencode import Schema, validators
class LinkForm(Schema):
__init__(self, fields):
for field in fields:
condition = fields[field]
field = validators.UnicodeString(condition)
I think it will not work. Is there a work around in this case?
Yes, you can add methods to an instance dynamically. No, you can't do what you want.
You can bind methods to the instance in the initializer. Unfortunately what you have there are descriptors and those must be bound to the class.
I would go the other way round—first define all form fields that might be used, and delete unneeded ones later.
Provided that you have:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
you could do either this:
def xy():
my_form = LinkForm()
del my_form.url
…
… or this:
def xy():
class CustomLinkForm(LinkForm):
pass
if …:
del CustomLinkForm.url
…
Disclaimer: I am not familiar with FormEncode, so it might depend on its inner workings which of these two versions actually works.
of course you can have a constructor with some arguments after self and these arguments will be the value for some members of your class if you have for instance
__init__(self, fields):
self.fields = []
for field in fields:
self.fields = self.fields + field
see this in Dive into Python
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
Classes can (and should) have doc strings too, just like modules and
functions.
init is called immediately after an instance of the
class is created. It would be tempting but incorrect to call this the
constructor of the class. It's tempting, because it looks like a
constructor (by convention, init is the first method defined for
the class), acts like one (it's the first piece of code executed in a
newly created instance of the class), and even sounds like one (“init”
certainly suggests a constructor-ish nature). Incorrect, because the
object has already been constructed by the time init is called,
and you already have a valid reference to the new instance of the
class. But init is the closest thing you're going to get to a
constructor in Python, and it fills much the same role.
The first
argument of every class method, including init, is always a
reference to the current instance of the class. By convention, this
argument is always named self. In the init method, self refers to
the newly created object; in other class methods, it refers to the
instance whose method was called. Although you need to specify self
explicitly when defining the method, you do not specify it when
calling the method; Python will add it for you automatically.
init methods can take any number of arguments, and just like
functions, the arguments can be defined with default values, making
them optional to the caller. In this case, filename has a default
value of None, which is the Python null value.
Note that in the later example you learn how to deal with inherited class, calling __init()__ for this inherited class.
To answer your not-a-question about class or instance variables, see this
Variables defined in the class definition are class variables; they
are shared by all instances. To create instance variables, they can be
set in a method with self.name = value. Both class and instance
variables are accessible through the notation “self.name”, and an
instance variable hides a class variable with the same name when
accessed in this way. Class variables can be used as defaults for
instance variables, but using mutable values there can lead to
unexpected results. For new-style classes, descriptors can be used to
create instance variables with different implementation details.

Must all Python instance variables be declared in def __init__?

Or can they be declared otherwise?
The code below does not work:
class BinaryNode():
self.parent = None
self.left_child = None
Do they need to be declared in __init__?
They do not have to be declared in __init__, but in order to set an instance variable using self, there needs to be a reference to self, and the place you are defining the variables does not.
However,
class BinaryNode():
parent = None
left_child = None
def run(self):
self.parent = "Foo"
print self.parent
print self.left_child
The output will be
Foo
None
To answer your question in the comment, yes. You can, in my example say:
bn = BinaryNode()
bn.new_variable = "Bar"
Or, as I showed, you can set a class level variable. All new instances of the class will get a copy of the class level variables at instantiation.
Perhaps you are not aware that you can pass arguments to the constructor:
class BinaryNode(object):
def __init__(self, parent=None, left_child=None):
self.parent = parent
self.left_child = left_child
bn = BinaryNode(node_parent, node_to_the_left)
Must all Python instance variables be declared in def __init__?
Short answer: no. But it really depends on how/where to use them.
Or can they be declared otherwise?
Yes they can be declared otherwise (not an instance variable). Since you're referring to variables inside a class, yes you can declare a local variable (for example) inside of it if you don't want to use __init__ constructor function that uses the keyword self.
The code below does not work:
class BinaryNode():
self.parent = None
self.left_child = None
What do you mean by not working? if you're referring to how most developers use a class, then you are right, it does not work in the sense that you can not create a class object (it's also called class instance) and then call one of its instance variables assuming they are declared properly (ie: declared INSIDE the init method that plays the role of the constructor method.)
In other words: if you declare a variable outside the constructor method init then it's called a class variable and not an instance variable.
To initiate an instance variable, it needs to be inside the init method that will actually construct (instantiate) the class instance (class object) along with its associated instance variables (instance attributes.)
for example:
if you have parent = None instead of self.parent = None you just created a local variable inside your class.
So the word self is there to hold the place for when you call the class instance is called, it's passed-in in lieu of self. Therefor the word self is just there as a parameter to hold a place for passing whatever instance variable we want to call in its place. So the word self is just doing a favor service here.
Similarly , when creating a class object and say you want to create an instance variable, you must use the attribute word self (it does not have to be self but since most python developers use it, using it became a convention and a good practice in python) that will work as a reference (a holder) to complete the work of the constructor function __init__ which will assign the argument value passed-in the class instance (object) created to be the new value of the instance variable copy that belongs to the class instance created.
Now, let's try another scenario to better solidify the concept:
What if we use the __init__ function but not the keyword self?
if you create a class object named object_x and then you want to call one of its instance variables named instance_y from the , then you execute the program, it will throw an error saying that the class object created does not have an attribute (instance variable).
It will be just a local variable with whatever value you assigned to it when you defined it.
The error occurs because it doesn't recognize it as one of the instance variables defined inside the class when it's missing the reference word self.
Nope. I love the #property variable for just this thing:
class Data(object):
"""give me some data, and I'll give you more"""
def __init__(self, some, others):
self.some = some
self.others = others
#property
def more(self):
"""you don't instantiate this with __init__, per say..."""
return zip(self.some, self.others)
>>> mydata = Data([1, 2, 3], ['a', 'b', 'c'])
>>> mydata.more
[(1, 'a'), (2, 'b'), (3, 'c')]
Also, you can have class level variables, but I call them class constants.
class Connection(object):
"""helps you connect to the server at work"""
YOUR_IP = '10.0.9.99'
def __init__(self, username, password):
self.ip = Connection.YOUR_IP
self.un = username
self.pw = password
#...and so on

python: set a class variable programmatically before other class variables get set?

i have a case where i create a class inside an outer function and then return that class. the class has a specified parent class. i would like that class variable to be accessible by class methods on the parent class, these methods are called at class initialization time. in summary, i need to be able to set a class variable (not hardcoded) so that it is available before initializing other, hardcoded class variables.
here's some sample code to make that clearer:
class Parent(object):
class_var = None
#classmethod
def get_class_var_times_two(cls):
return cls.class_var * 2
def outer_function(class_var_value):
class Child(Parent):
other_var = Parent.get_class_var_times_two() # <-- at this point, somehow Child's class_var is set to class_var_value
Not sure if this is even possible in python. Maybe class_var_value doesn't need to be passed through the outer function. I tried using metaclasses and forcing the variable through in the class attribute dictinoary, but couldn't figure out how to set class_var on Child early enough so that it was set prior to initializing other_var. If that was possible, then this would all work. Any thoughts are appreciated!
Edit: also considered making other_var a lazy property, but that isn't an option for my use case.
Calling Parent.get_class_var_times_two() calls the function with cls = Parent, and so consequently the value of Parent.class_var will be used (regardless of what context you call the function from).
So, what you want to do is call Child.get_class_var_times_two(). Trouble is, Child doesn't get defined until the class block finishes. You therefore need to do something like this (assuming you don't use a metaclass):
def outer_function(class_var_value):
class Child(Parent):
class_var = class_var_value
Child.other_var = Child.get_class_var_times_two()

Categories

Resources