While investigating Ruby I came across this to create a simple Struct-like class:
Person = Struct.new(:forname, :surname)
person1 = Person.new('John', 'Doe')
puts person1 #<struct Person forname="John", surname="Doe">
Which raised a few Python questions for me. I have written a [VERY] basic clone of this mechanism in Python:
def Struct(*args):
class NewStruct:
def __init__(self):
for arg in args:
self.__dict__[arg] = None
return NewStruct
>>> Person = Struct('forename', 'surname')
>>> person1 = Person()
>>> person2 = Person()
>>> person1.forename, person1.surname = 'John','Doe'
>>> person2.forename, person2.surname = 'Foo','Bar'
>>> person1.forename
'John'
>>> person2.forename
'Foo'
Is there already a similar mechanism in Python to handle this? (I usually just use dictionaries).
How would I get the Struct()
function to create the correct __init__()
arguments. (in this case I would like to perform person1 = Person('John', 'Doe')
Named Arguments if possible: person1 = Person(surname='Doe', forename='John')
I Would like, as a matter of interest, to have Question 2 answered even if there is a better Python mechanism to do this.
Python does not exactly have the same thing as a struct in Matlab. You can achieve something like it by defining an empty class and then defining attributes of the class. You can check if an object has a particular attribute using hasattr.
In C++, structs and classes are pretty much the same; the only difference is that where access modifiers (for member variables, methods, and base classes) in classes default to private, access modifiers in structs default to public.
The only difference between a struct and class in C++ is the default accessibility of member variables and methods. In a struct they are public; in a class they are private.
Without taking pages and pages to go into the details, think of a C struct as a way to organize data, while a Python (or C++ or Objective-C) "class" is a way to organize not only your data, but the operations for that data.
If you're using Python 2.6, try the standard library namedtuple class.
>>> from collections import namedtuple
>>> Person = namedtuple('Person', ('forename', 'surname'))
>>> person1 = Person('John', 'Doe')
>>> person2 = Person(forename='Adam', surname='Monroe')
>>> person1.forename
'John'
>>> person2.surname
'Monroe'
Edit: As per comments, there is a backport for earlier versions of Python
If you're running python <2.6 or would like to extend your class to do more stuff, I would suggest using the type()
builtin. This has the advantage over your solution in that the setting up of __dict__
happens at class creation rather than instantiation. It also doesn't define an __init__
method and thus doesn't lead to strange behavior if the class calls __init__
again for some reason. For example:
def Struct(*args, **kwargs):
name = kwargs.pop("name", "MyStruct")
kwargs.update(dict((k, None) for k in args))
return type(name, (object,), kwargs)
Used like so:
>>> MyStruct = Struct("forename", "lastname")
Equivalent to:
class MyStruct(object):
forename = None
lastname = None
While this:
>>> TestStruct = Struct("forename", age=18, name="TestStruct")
Is equivalent to:
class TestStruct(object):
forename = None
age = 18
Update
Additionally, you can edit this code to very easily prevent assignment of other variables than the ones specificed. Just change the Struct() factory to assign __slots__
.
def Struct(*args, **kwargs):
name = kwargs.pop("name", "MyStruct")
kwargs.update(dict((k, None) for k in args))
kwargs['__slots__'] = kwargs.keys()
return type(name, (object,), kwargs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With